百行代碼帶你實現(xiàn)通過872條Promise/A+用例的Promise
前端瓶子君,關(guān)注公眾號
回復(fù)算法,加入前端編程面試算法每日一題群
前言
一直聽說想成為一名高級前端程序員需要理解一些源碼,那就從 Promise 開始吧,作者盡量用最少的語言讓你理解 Promise
準(zhǔn)備
Promises/A+原文[2]
Promises/A+譯文[3]
安裝 Promise 測試工具
npm?i?promises-aplus-tests?-g
復(fù)制代碼
運行測試工具,檢測 Promise 是否符合規(guī)范
promises-aplus-tests?[promise文件名]
復(fù)制代碼
完整代碼先過用例
const?PENDING?=?'PENDING';
const?FULFILLED?=?'FULFILLED';
const?REJECTED?=?'REJECTED';
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
????this.state?=?PENDING;
????this.value?=?null;
????this.reason?=?null;
????this.onFulfilledCallbacks?=?[];
????this.onRejectedCallbacks?=?[];
????const?resolve?=?(value)?=>?{
??????if?(this.state?===?PENDING)?{
????????this.state?=?FULFILLED;
????????this.value?=?value;
????????this.onFulfilledCallbacks.forEach((fn)?=>?fn());
??????}
????};
????const?reject?=?(reason)?=>?{
??????if?(this.state?===?PENDING)?{
????????this.state?=?REJECTED;
????????this.reason?=?reason;
????????this.onRejectedCallbacks.forEach((fn)?=>?fn());
??????}
????};
????try?{
??????executor(resolve,?reject);
????}?catch?(e)?{
??????this.reject(e);
????}
??}
??then(onFulfilled,?onRejected)?{
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
????let?promise2?=?new?Promise((resolve,?reject)?=>?{
??????if?(this.state?===?FULFILLED)?{
????????setTimeout(()?=>?{
??????????try?{
????????????const?x?=?onFulfilled(this.value);
????????????resolvePromise(promise2,?x,?resolve,?reject);
??????????}?catch?(e)?{
????????????reject(e);
??????????}
????????},?0);
??????}
??????if?(this.state?===?REJECTED)?{
????????setTimeout(()?=>?{
??????????try?{
????????????const?x?=?onRejected(this.reason);
????????????resolvePromise(promise2,?x,?resolve,?reject);
??????????}?catch?(e)?{
????????????reject(e);
??????????}
????????},?0);
??????}
??????if?(this.state?===?PENDING)?{
????????this.onFulfilledCallbacks.push(()?=>?{
??????????setTimeout(()?=>?{
????????????try?{
??????????????const?x?=?onFulfilled(this.value);
??????????????resolvePromise(promise2,?x,?resolve,?reject);
????????????}?catch?(e)?{
??????????????reject(e);
????????????}
??????????});
????????});
????????this.onRejectedCallbacks.push(()?=>?{
??????????setTimeout(()?=>?{
????????????try?{
??????????????const?x?=?onRejected(this.reason);
??????????????resolvePromise(promise2,?x,?resolve,?reject);
????????????}?catch?(e)?{
??????????????reject(e);
????????????}
??????????});
????????});
??????}
????});
????return?promise2;
??}
}
const?resolvePromise?=?(promise2,?x,?resolve,?reject)?=>?{
??if?(promise2?===?x)
????return?reject(
??????new?TypeError('Chaining?cycle?detected?for?promise?#' )
????);
??if?((typeof?x?===?'object'?&&?x?!==?null)?||?typeof?x?===?'function')?{
????let?called;
????try?{
??????const?then?=?x.then;
??????if?(typeof?then?!==?'function')?resolve(x);
??????else?{
????????then.call(
??????????x,
??????????(value)?=>?{
????????????if?(called)?return;
????????????called?=?true;
????????????resolvePromise(promise2,?value,?resolve,?reject);
??????????},
??????????(reason)?=>?{
????????????if?(called)?return;
????????????called?=?true;
????????????reject(reason);
??????????}
????????);
??????}
????}?catch?(err)?{
??????if?(called)?return;
??????called?=?true;
??????reject(err);
????}
??}?else?{
????resolve(x);
??}
};
Promise.defer?=?Promise.deferred?=?function?()?{
??let?dfd?=?{};
??dfd.promise?=?new?Promise((resolve,?reject)?=>?{
????dfd.resolve?=?resolve;
????dfd.reject?=?reject;
??});
??return?dfd;
};
module.exports?=?Promise;
復(fù)制代碼
完整代碼127行,增加 Promise 測試代碼一共 136 行代碼。
如何測試
在 VS Code 新建文件 promise.jspromise.jspromise.js 文件
//?promise代碼
class?Promise?{
??constructor()?{}
??then()?{}
??catch()?{}
}
//?測試代碼
Promise.defer?=?Promise.deferred?=?function?()?{
??let?dfd?=?{};
??dfd.promise?=?new?Promise((resolve,?reject)?=>?{
????dfd.resolve?=?resolve;
????dfd.reject?=?reject;
??});
??return?dfd;
};
module.exports?=?Promise;
復(fù)制代碼
在 promise.jspromise.jspromise.js 文件所在目錄打開終端,輸入下面命令即可測試 Promise 是否符合規(guī)范
promises-aplus-tests?promise.js
復(fù)制代碼
后續(xù)講解,不再解釋測試代碼,只討論 Promise 代碼了
請緊跟思路,本篇文章核心開始了
聲明 Promise 類
Promise 常用的有 then 方法 和 catch,先用 ES6 語法聲明一個 Promise 類
這點不難理解吧?
class?Promise?{
??constructor()?{}
??then()?{}
??catch()?{}
}
復(fù)制代碼
constructor
正常使用 Promise 一般 如下圖所示, new Promise(參數(shù)是一個函數(shù))
let?p1?=?new?Promise((resolve)?=>?{
??setTimeout(()?=>?{
????resolve(1);
??},?1000);
});
復(fù)制代碼
所以 在 Promise 類的 constructor 使用 executor 形參接收這個參數(shù),這點不難理解吧?
class?Promise?{
??constructor(executor)?{}
??then()?{}
??catch()?{}
}
復(fù)制代碼
繼續(xù):
executor 是用戶輸入的參數(shù),咱們不能相信用戶一定會使用一個函數(shù)作為 new Promise(參數(shù)) 對不對?
所以這里就需要判斷一下 executor 是否是一個函數(shù)。
很好理解吧?
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
??}
??then()?{}
??catch()?{}
}
復(fù)制代碼
executor
constructor 這節(jié)已經(jīng)知道 executor 是個函數(shù)了,executor 函數(shù)也是有參數(shù)的呀。
如下 Promise 使用代碼
let?p1?=?new?Promise((resolve,?reject)?=>?{
??setTimeout(()?=>?{
????Math.random()?>?0.5???resolve('正確')?:?reject('錯誤');
??},?1000);
});
p1.then((value)?=>?{
??console.log(value);
});
復(fù)制代碼

Promises/A+ 規(guī)范中說:resolve 是進行成功的一系列操作,reject 是失敗的一些操作,還有成功原因,失敗原因?這些咱們的 Promise 都要有,都加上
resolve 和 reject
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
????//?promise?被解決時傳遞給解決回調(diào)的值
????this.value?=?null;
????//?promise?被拒絕時傳遞給解決回調(diào)的值
????this.reason?=?null;
????//?成功的一系列操作
????const?resolve?=?()?=>?{};
????//失敗的一些操作
????const?reject?=?()?=>?{};
????executor(resolve,?reject);
??}
??then()?{}
??catch()?{}
}
復(fù)制代碼
狀態(tài)
Promises/A+譯文[4]

Promises/A+ 規(guī)范中說,Promise 要有 3 種狀態(tài)。咱們在代碼中將這三種狀態(tài)加上,這很好理解吧
常量命名用大寫,這點可以理解的
PENDING 、FULFILLED 和 REJECTED
const?PENDING?=?'PENDING';
const?FULFILLED?=?'FULFILLED';
const?REJECTED?=?'REJECTED';
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
??}
??then()?{}
??catch()?{}
}
復(fù)制代碼
要求說,Pending 狀態(tài)只能去 Fulfilled 或者 Rejected 且不可變,這就需要一個變量記錄 Promise 狀態(tài)值, 并且狀態(tài)值初始值為 Pending 這點可以理解吧
this.state
const?PENDING?=?'PENDING';
const?FULFILLED?=?'FULFILLED';
const?REJECTED?=?'REJECTED';
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
????this.state?=?PENDING;
????this.value?=?null;
????this.reason?=?null;
????const?resolve?=?()?=>?{};
????const?reject?=?()?=>?{};
????executor(resolve,?reject);
??}
??then()?{}
??catch()?{}
}
復(fù)制代碼
Pending 狀態(tài)只能去 Fulfilled 或者 Rejected 意味著 resolve 和 reject 只有在 Pending 可以執(zhí)行,沒問題吧。
所以需要在 resolve 和 reject 函數(shù)中加判斷
const?PENDING?=?'PENDING';
const?FULFILLED?=?'FULFILLED';
const?REJECTED?=?'REJECTED';
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
????this.state?=?PENDING;
????this.value?=?null;
????this.reason?=?null;
????const?resolve?=?()?=>?{
??????//?PENDING狀態(tài)才能執(zhí)行,執(zhí)行完成修改狀態(tài)為FULFILLED
??????if?(this.state?===?PENDING)?{
????????this.state?=?FULFILLED;
??????}
????};
????const?reject?=?()?=>?{
??????//?PENDING狀態(tài)才能執(zhí)行,執(zhí)行完成修改狀態(tài)為?REJECTED
??????if?(this.state?===?PENDING)?{
????????this.state?=?REJECTED;
??????}
????};
????executor(resolve,?reject);
??}
??then()?{}
??catch()?{}
}
復(fù)制代碼
執(zhí)行完成功或者異常函數(shù)是不是要有成功或者異常數(shù)據(jù)呀,這些回調(diào)的值是不是需要保存到類中,在 then 方法中返回?
添加上
value 和 reason
const?PENDING?=?'PENDING';
const?FULFILLED?=?'FULFILLED';
const?REJECTED?=?'REJECTED';
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
????this.state?=?PENDING;
????this.value?=?null;
????this.reason?=?null;
????const?resolve?=?(value)?=>?{
??????if?(this.state?===?PENDING)?{
????????this.state?=?FULFILLED;
????????//?解決時傳遞給解決回調(diào)的值
????????this.value?=?value;
??????}
????};
????const?reject?=?(reason)?=>?{
??????if?(this.state?===?PENDING)?{
????????this.state?=?REJECTED;
????????//?拒絕時傳遞給解決回調(diào)的值
????????this.reason?=?reason;
??????}
????};
????executor(resolve,?reject);
??}
??then()?{}
??catch()?{}
}
復(fù)制代碼
constructor 這就完成了嗎?不,還差一步。
executor 是個函數(shù),這在上文中有描述,但是函數(shù)有沒有可能執(zhí)行錯誤,直接執(zhí)行這個函數(shù)報錯,報錯怎么處理?try/catch 大法嘍
const?PENDING?=?'PENDING';
const?FULFILLED?=?'FULFILLED';
const?REJECTED?=?'REJECTED';
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
????this.state?=?PENDING;
????this.value?=?null;
????this.reason?=?null;
????const?resolve?=?(value)?=>?{
??????if?(this.state?===?PENDING)?{
????????this.state?=?FULFILLED;
????????//?解決時傳遞給解決回調(diào)的值
????????this.value?=?value;
??????}
????};
????const?reject?=?(reason)?=>?{
??????if?(this.state?===?PENDING)?{
????????this.state?=?REJECTED;
????????//?拒絕時傳遞給解決回調(diào)的值
????????this.reason?=?reason;
??????}
????};
????try?{
??????//?如果函數(shù)順利執(zhí)行,執(zhí)行函數(shù)
??????executor(resolve,?reject);
????}?catch?(error)?{
??????//?函數(shù)拋出異常,將異常信息通過?reject?返回
??????reject(error);
????}
??}
??then()?{}
??catch()?{}
}
復(fù)制代碼
Then
單獨寫 then 這個函數(shù),暫時忽略 constructor 代碼吧。代碼太多容易混淆。讀者覺得呢?
then()?{}
復(fù)制代碼
Promises/A+譯文[5]

根據(jù)規(guī)范中規(guī)定 then 要有兩個參數(shù),并且這兩個參數(shù)需要是函數(shù),如果不是函數(shù)需要忽略
所以 then 代碼如下;不難理解吧
then(onFulfilled,?onRejected){
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
}
復(fù)制代碼
onFulfilled 和 onRejected
接著看規(guī)范描述

onFulfilled和onRejected調(diào)用次數(shù)不可超過一次,
then(onFulfilled,?onRejected)?{
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
????//?只執(zhí)行一次
????if?(this.state?===?Promise.FULFILLED)?{
??????onFulfilled(this.value);
????}
????if?(this.state?===?Promise.REJECTED)?{
??????onRejected(this.reason);
????}
??}
復(fù)制代碼
resolve 支持異步
這樣就可以了嗎??不不不
如果 Promise 中 resolve 是在異步函數(shù)中執(zhí)行的,目前我寫的 Promise 代碼中 console 并不會執(zhí)行。
let?p2?=?new?Promise((resolve)?=>?{
??setTimeout(()?=>?{
????resolve(2);
??},?1000);
});
p2.then((value)?=>?{
??console.log(value);
});
復(fù)制代碼
原因是執(zhí)行 .then函數(shù)的時候 Promise 狀態(tài)是 Pending ,當(dāng)前我在 Promise.then方法中只寫了 狀態(tài)為 FULFILLED 和 REJECTED 的處理
所以.then函數(shù)還要處理狀態(tài)位PENDING 的處理,pending 狀態(tài)下,將.then 函數(shù)的入?yún)⑾确旁跀?shù)組中,在異步執(zhí)行 resolve 是調(diào)用
還有問題嗎?
有的
then異步
console.log(1);
let?p2?=?new?Promise((resolve)?=>?{
??resolve(4);
??console.log(2);
});
p2.then((value)?=>?{
??console.log(value);
});
console.log(3);
//??1,2,3,4
復(fù)制代碼
正常返回 1,2,3,4 現(xiàn)在我寫的 promise 返回 1、2、4、3
什么原因呢?原因是 .then 中的函數(shù)立即執(zhí)行了,這不符合標(biāo)準(zhǔn)呀,解決辦法是給 .then 函數(shù)添加 setTimeout 模擬異步
??then(onFulfilled,?onRejected)?{
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
????if?(this.state?===?FULFILLED)?{
??????setTimeout(()?=>?{
????????onFulfilled(this.value);
??????});
????}
????if?(this.state?===?REJECTED)?{
??????setTimeout(()?=>?{
????????onRejected(this.reason);
??????});
????}
????if?(this.state?===?PENDING)?{
??????this.onFulfilledCallbacks.push(()?=>?{
????????setTimeout(()?=>?{
??????????onFulfilled(this.value);
????????});
??????});
??????this.onRejectedCallbacks.push(()?=>?{
????????setTimeout(()?=>?{
??????????onRejected(this.reason);
????????});
??????});
????}
????let?promise2?=?new?Promise(()?=>?{});
????return?promise2;
??}
}
復(fù)制代碼
Promise 的數(shù)組需要在 constructor 中聲明,并且在 resolve 中執(zhí)行,所以代碼 Promise 到這里全部代碼如下:
const?PENDING?=?'PENDING';
const?FULFILLED?=?'FULFILLED';
const?REJECTED?=?'REJECTED';
class?Promise?{
??constructor(executor)?{
????if?(typeof?executor?!==?'function')?{
??????return?new?TypeError(`Promise?resolver?${executor}?is?not?a?function`);
????}
????this.state?=?PENDING;
????this.value?=?null;
????this.reason?=?null;
????this.onFulfilledCallbacks?=?[];
????this.onRejectedCallbacks?=?[];
????const?resolve?=?(value)?=>?{
??????if?(this.state?===?PENDING)?{
????????this.state?=?FULFILLED;
????????this.value?=?value;
????????this.onFulfilledCallbacks.forEach((fn)?=>?fn());
??????}
????};
????const?reject?=?(reason)?=>?{
??????if?(this.state?===?PENDING)?{
????????this.state?=?REJECTED;
????????this.reason?=?reason;
????????this.onRejectedCallbacks.forEach((fn)?=>?fn());
??????}
????};
????try?{
??????executor(resolve,?reject);
????}?catch?(e)?{
??????this.reject(e);
????}
??}
??then(onFulfilled,?onRejected)?{
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
????if?(this.state?===?FULFILLED)?{
??????setTimeout(()?=>?{
????????onFulfilled(this.value);
??????});
????}
????if?(this.state?===?REJECTED)?{
??????setTimeout(()?=>?{
????????onRejected(this.reason);
??????});
????}
????if?(this.state?===?PENDING)?{
??????this.onFulfilledCallbacks.push(()?=>?{
????????setTimeout(()?=>?{
??????????onFulfilled(this.value);
????????});
??????});
??????this.onRejectedCallbacks.push(()?=>?{
????????setTimeout(()?=>?{
??????????onRejected(this.reason);
????????});
??????});
????}
??}
}
復(fù)制代碼
寫到這里,我去測試了一下顯示有 806 個異常;也就是說通過了 66 個測試用例。繼續(xù)努力
then如何返回一個新的Promise
接著看規(guī)范描述: 
then? 方法必須返回一個 ?promise? 對象
??then(onFulfilled,?onRejected)?{
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
????if?(this.state?===?FULFILLED)?{
??????setTimeout(()?=>?{
????????onFulfilled(this.value);
??????});
????}
????if?(this.state?===?REJECTED)?{
??????setTimeout(()?=>?{
????????onRejected(this.reason);
??????});
????}
????if?(this.state?===?PENDING)?{
??????this.onFulfilledCallbacks.push(()?=>?{
????????setTimeout(()?=>?{
??????????onFulfilled(this.value);
????????});
??????});
??????this.onRejectedCallbacks.push(()?=>?{
????????setTimeout(()?=>?{
??????????onRejected(this.reason);
????????});
??????});
????}
????//?返回一個新的?promise?對象
????let?promise2?=?new?Promise(()?=>?{});
????return?promise2;
??}
復(fù)制代碼
可以理解吧?每次 .then 都返回一個新的 promise 對象,.then 方法是不是就可以一直調(diào)用下去了
這里為什么不可以直接返回 this,比如 jQuery 不就是直接返回 this 實現(xiàn)鏈?zhǔn)秸{(diào)用的嗎?
因為 promise 有 3 種狀態(tài),且狀態(tài)不可逆,所以必須返回一個新的 promise 對象
then返回Promise解決過程
接著看規(guī)范描述:
如果 ? onFulfilled? 或者 ?onRejected? 返回一個值 ?x?,則運行下面的 ?Promise 解決過程:[[Resolve]](promise2, x)如果 ? onFulfilled? 或者 ?onRejected? 拋出一個異常 ?e?,則 ?promise2? 必須拒絕執(zhí)行,并返回拒因 ?e如果 ? onFulfilled? 不是函數(shù)且 ?promise1? 成功執(zhí)行,?promise2? 必須成功執(zhí)行并返回相同的值如果 ? onRejected? 不是函數(shù)且 ?promise1? 拒絕執(zhí)行,?promise2? 必須拒絕執(zhí)行并返回相同的據(jù)因
第一句
需要確定,?onFulfilled? 或者 ?onRejected? 返回一個值 ?x要執(zhí)行 Promise2
修改 then 代碼如下:
??then(onFulfilled,?onRejected)?{
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
????let?promise2?=?new?Promise((resolve,?reject)?=>?{
??????if?(this.state?===?FULFILLED)?{
????????setTimeout(()?=>?{
?????????const?x?=?onFulfilled(this.value);
????????});
??????}
??????if?(this.state?===?REJECTED)?{
????????setTimeout(()?=>?{
??????????const?x?=?onRejected(this.reason);
????????});
??????}
??????if?(this.state?===?PENDING)?{
????????this.onFulfilledCallbacks.push(()?=>?{
??????????setTimeout(()?=>?{
???????????const?x?=??onFulfilled(this.value);
??????????});
????????});
????????this.onRejectedCallbacks.push(()?=>?{
??????????setTimeout(()?=>?{
???????????const?x?=??onRejected(this.reason);
??????????});
????????});
??????}
????});
????return?promise2;
??}
}
復(fù)制代碼
第二句
如果 ?onFulfilled? 或者 ?onRejected? 拋出一個異常 ?e?,則 ?promise2? 必須拒絕執(zhí)行,并返回拒因 ?e
使用 try/catch 捕捉 ?onFulfilled? 或者 ?onRejected 拋出的異常
then(onFulfilled,?onRejected)?{
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
????let?promise2?=?new?Promise((resolve,?reject)?=>?{
??????if?(this.state?===?FULFILLED)?{
????????setTimeout(()?=>?{
??????????try?{
????????????const?x?=?onFulfilled(this.value);
??????????}?catch?(error)?{
????????????reject(error);
??????????}
????????});
??????}
??????if?(this.state?===?REJECTED)?{
????????setTimeout(()?=>?{
??????????try?{
????????????const?x?=?onRejected(this.reason);
??????????}?catch?(error)?{
????????????reject(error);
??????????}
????????});
??????}
??????if?(this.state?===?PENDING)?{
????????this.onFulfilledCallbacks.push(()?=>?{
??????????setTimeout(()?=>?{
????????????try?{
??????????????const?x?=?onFulfilled(this.value);
????????????}?catch?(error)?{
??????????????reject(error);
????????????}
??????????});
????????});
????????this.onRejectedCallbacks.push(()?=>?{
??????????setTimeout(()?=>?{
????????????try?{
??????????????const?x?=?onRejected(this.reason);
????????????}?catch?(error)?{
??????????????reject(error);
????????????}
??????????});
????????});
??????}
????});
????return?promise2;
??}
復(fù)制代碼
第三句
如果 ?onFulfilled? 不是函數(shù)且 ?promise1? 成功執(zhí)行,?promise2? 必須成功執(zhí)行并返回相同的值
promise2 執(zhí)行成功并返回值,這句簡單,在返回 x 的地方直接 resolve(x) 不就可以了嗎?
then(onFulfilled,?onRejected)?{
??if?(typeof?onFulfilled?!==?'function')?{
????onFulfilled?=?(value)?=>?value;
??}
??if?(typeof?onRejected?!==?'function')?{
????onRejected?=?(err)?=>?{
??????throw?err;
????};
??}
??let?promise2?=?new?Promise((resolve,?reject)?=>?{
????if?(this.state?===?FULFILLED)?{
??????setTimeout(()?=>?{
????????try?{
??????????const?x?=?onFulfilled(this.value);
??????????resolve(x);
????????}?catch?(error)?{
??????????reject(error);
????????}
??????});
????}
????if?(this.state?===?REJECTED)?{
??????setTimeout(()?=>?{
????????try?{
??????????const?x?=?onRejected(this.reason);
??????????//?這里直接?resolve?并并且返回?x
??????????resolve(x);
????????}?catch?(error)?{
??????????reject(error);
????????}
??????});
????}
????if?(this.state?===?PENDING)?{
??????this.onFulfilledCallbacks.push(()?=>?{
????????setTimeout(()?=>?{
??????????try?{
????????????const?x?=?onFulfilled(this.value);
????????????resolve(x);
??????????}?catch?(error)?{
????????????reject(error);
??????????}
????????});
??????});
??????this.onRejectedCallbacks.push(()?=>?{
????????setTimeout(()?=>?{
??????????try?{
????????????const?x?=?onRejected(this.reason);
????????????resolve(x);
??????????}?catch?(error)?{
????????????reject(error);
??????????}
????????});
??????});
????}
??});
??return?promise2;
}
復(fù)制代碼
如果 x 是基本數(shù)據(jù)類型可以,考慮一下,如果 x 是引用數(shù)據(jù)類型,是函數(shù),甚至是 Promise 呢?
所以這里需要對 x 的數(shù)據(jù)類型判斷
既然自成一體,索性增加一個方法執(zhí)行這些 x 值
方法名為:resolvePromise
?then(onFulfilled,?onRejected)?{
????if?(typeof?onFulfilled?!==?'function')?{
??????onFulfilled?=?(value)?=>?value;
????}
????if?(typeof?onRejected?!==?'function')?{
??????onRejected?=?(err)?=>?{
????????throw?err;
??????};
????}
????let?promise2?=?new?Promise((resolve,?reject)?=>?{
??????if?(this.state?===?FULFILLED)?{
????????setTimeout(()?=>?{
??????????try?{
????????????const?x?=?onFulfilled(this.value);
????????????resolvePromise(promise2,?x,?resolve,?reject);
??????????}?catch?(error)?{
????????????reject(error);
??????????}
????????});
??????}
??????if?(this.state?===?REJECTED)?{
????????setTimeout(()?=>?{
??????????try?{
????????????const?x?=?onRejected(this.reason);
????????????resolvePromise(promise2,?x,?resolve,?reject);
??????????}?catch?(error)?{
????????????reject(error);
??????????}
????????});
??????}
??????if?(this.state?===?PENDING)?{
????????this.onFulfilledCallbacks.push(()?=>?{
??????????setTimeout(()?=>?{
????????????try?{
??????????????const?x?=?onFulfilled(this.value);
??????????????resolvePromise(promise2,?x,?resolve,?reject);
????????????}?catch?(error)?{
??????????????reject(error);
????????????}
??????????});
????????});
????????this.onRejectedCallbacks.push(()?=>?{
??????????setTimeout(()?=>?{
????????????try?{
??????????????const?x?=?onRejected(this.reason);
??????????????resolvePromise(promise2,?x,?resolve,?reject);
????????????}?catch?(error)?{
??????????????reject(error);
????????????}
??????????});
????????});
??????}
????});
????return?promise2;
??}
??function?resolvePromise(promise2,?x,?resolve,?reject){
??}
復(fù)制代碼
resolvePromise
接下來開始寫 resolvePromise 這個函數(shù)
判斷 x 只不是 promise 自己
promise 不能循環(huán)調(diào)用,
function?resolvePromise(promise2,?x,?resolve,?reject)?{
??if?(promise2?===?x)?{
????return?reject(
??????new?TypeError('Chaining?cycle?detected?for?promise?#' )
????);
??}
}
復(fù)制代碼
判斷 x 是不是引用數(shù)據(jù)類型
如果不是引用數(shù)據(jù)類型,直接執(zhí)行 resolve(x)
function?resolvePromise(promise2,?x,?resolve,?reject)?{
??if?(promise2?===?x)?{
????return?reject(
??????new?TypeError('Chaining?cycle?detected?for?promise?#' )
????);
??}
??if?((typeof?x?===?'object'?&&?x?!==?null)?||?typeof?x?===?'function')?{
??}?else?{
????resolve(x);
??}
}
復(fù)制代碼
如果是引用數(shù)據(jù)類型,判斷數(shù)據(jù)中是否有 then 這個屬性,如果有 then 不是函數(shù),直接執(zhí)行 resolve(x)
這里解釋一下:如果 then 是函數(shù),表示 x 可能是 Promise 對象,需要特殊處理,如果不是函數(shù),當(dāng)作一般對象處理
function?resolvePromise(promise2,?x,?resolve,?reject)?{
??if?(promise2?===?x)?{
????return?reject(
??????new?TypeError('Chaining?cycle?detected?for?promise?#' )
????);
??}
??if?((typeof?x?===?'object'?&&?x?!==?null)?||?typeof?x?===?'function')?{
????const?then?=?x.then;
????if?(typeof?then?!==?'function')?{
??????resolve(x);
????}?else?{
????}
??}?else?{
????resolve(x);
??}
}
復(fù)制代碼
當(dāng)然,只要是代碼就有可能出現(xiàn)異常,所以這里需要 try/catch 捕捉一些可能的異常
function?resolvePromise(promise2,?x,?resolve,?reject)?{
??if?(promise2?===?x)?{
????return?reject(
??????new?TypeError('Chaining?cycle?detected?for?promise?#' )
????);
??}
??if?((typeof?x?===?'object'?&&?x?!==?null)?||?typeof?x?===?'function')?{
????try?{
??????const?then?=?x.then;
??????if?(typeof?then?!==?'function')?{
????????resolve(x);
??????}?else?{
??????}
????}?catch?(err)?{
??????reject(err);
????}
??}?else?{
????resolve(x);
??}
}
復(fù)制代碼
如果 then 是函數(shù)
then 是函數(shù),執(zhí)行 then。因為此時的 then 是從 x 上獲取的,所以要調(diào)用 call 方法將 then 函數(shù)的 this 重新指向 x
function?resolvePromise(promise2,?x,?resolve,?reject)?{
??if?(promise2?===?x)?{
????return?reject(
??????new?TypeError('Chaining?cycle?detected?for?promise?#' )
????);
??}
??if?((typeof?x?===?'object'?&&?x?!==?null)?||?typeof?x?===?'function')?{
????try?{
??????const?then?=?x.then;
??????if?(typeof?then?!==?'function')?{
????????resolve(x);
??????}?else?{
????????then.call(
??????????x,
??????????(value)?=>?{
????????????resolvePromise(promise2,?value,?resolve,?reject);
??????????},
??????????(reason)?=>?{
????????????reject(reason);
??????????}
????????);
??????}
????}?catch?(err)?{
??????reject(err);
????}
??}?else?{
????resolve(x);
??}
}
復(fù)制代碼
上述代碼基本完成了 Promise 的功能,但是還有一點規(guī)范文檔上說:
如果 resolvePromise 和 rejectPromise 均被調(diào)用,或者被同一參數(shù)調(diào)用了多次,則優(yōu)先采用首次調(diào)用并忽略剩下的調(diào)用
這需要增加標(biāo)識位 calledcalledcalled , called為true直接返回,
const?resolvePromise?=?(promise2,?x,?resolve,?reject)?=>?{
??if?(promise2?===?x)
????return?reject(
??????new?TypeError('Chaining?cycle?detected?for?promise?#' )
????);
??if?((typeof?x?===?'object'?&&?x?!==?null)?||?typeof?x?===?'function')?{
????let?called;
????try?{
??????const?then?=?x.then;
??????if?(typeof?then?!==?'function')?resolve(x);
??????else?{
????????then.call(
??????????x,
??????????(value)?=>?{
????????????if?(called)?return;
????????????called?=?true;
????????????resolvePromise(promise2,?value,?resolve,?reject);
??????????},
??????????(reason)?=>?{
????????????if?(called)?return;
????????????called?=?true;
????????????reject(reason);
??????????}
????????);
??????}
????}?catch?(err)?{
??????if?(called)?return;
??????called?=?true;
??????reject(err);
????}
??}?else?{
????resolve(x);
??}
};
復(fù)制代碼
結(jié)語
雖然我想用盡量少的語言去描述或者講解這個 Promise 。但是最后依然用了將近4000字描述這個東西是什么。作者目前水平有限,只得盡量將 Promise 描述清楚。如有任何意見和建議歡迎評論區(qū)留言討論。
關(guān)于本文
作者:北斗落凡塵
https://juejin.cn/post/7065693195799265287
