<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          百行代碼實現(xiàn)通過872條Promise/A+用例的Promise

          共 22997字,需瀏覽 46分鐘

           ·

          2022-04-29 02:50

          點擊上方?前端Q,關注公眾號

          回復加群,加入前端Q技術交流群


          前言

          一直聽說想成為一名高級前端程序員需要理解一些源碼,那就從 Promise 開始吧,作者盡量用最少的語言讓你理解 Promise

          準備

          Promises/A+原文[2]
          Promises/A+譯文[3]

          安裝 Promise 測試工具

          npm?i?promises-aplus-tests?-g
          復制代碼

          運行測試工具,檢測 Promise 是否符合規(guī)范

          promises-aplus-tests?[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;
          ??????};
          ????}
          ????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;


          復制代碼

          完整代碼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;
          復制代碼

          在 promise.jspromise.jspromise.js 文件所在目錄打開終端,輸入下面命令即可測試 Promise 是否符合規(guī)范

          promises-aplus-tests?promise.js
          復制代碼

          后續(xù)講解,不再解釋測試代碼,只討論 Promise 代碼了

          請緊跟思路,本篇文章核心開始了

          聲明 Promise 類

          Promise 常用的有 then 方法 和 catch,先用 ES6 語法聲明一個 Promise 類

          這點不難理解吧?

          class?Promise?{
          ??constructor()?{}
          ??then()?{}
          ??catch()?{}
          }
          復制代碼

          constructor

          正常使用 Promise 一般 如下圖所示, new Promise(參數(shù)是一個函數(shù))

          let?p1?=?new?Promise((resolve)?=>?{
          ??setTimeout(()?=>?{
          ????resolve(1);
          ??},?1000);
          });
          復制代碼

          所以 在 Promise 類的 constructor 使用 executor 形參接收這個參數(shù),這點不難理解吧?

          class?Promise?{
          ??constructor(executor)?{}
          ??then()?{}
          ??catch()?{}
          }
          復制代碼

          繼續(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()?{}
          }
          復制代碼

          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);
          });
          復制代碼
          image.png

          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()?{}
          }
          復制代碼

          狀態(tài)

          Promises/A+譯文[4]

          image.png

          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()?{}
          }
          復制代碼

          要求說,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()?{}
          }
          復制代碼

          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()?{}
          }
          復制代碼

          執(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()?{}
          }
          復制代碼

          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()?{}
          }
          復制代碼

          Then

          單獨寫 then 這個函數(shù),暫時忽略 constructor 代碼吧。代碼太多容易混淆。讀者覺得呢?

          then()?{}
          復制代碼

          Promises/A+譯文[5]

          image.png

          根據(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;
          ??????};
          ????}
          }
          復制代碼

          onFulfilled 和 onRejected

          接著看規(guī)范描述

          image.png

          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);
          ????}
          ??}

          復制代碼

          resolve 支持異步

          這樣就可以了嗎??不不不

          如果 Promise 中 resolve 是在異步函數(shù)中執(zhí)行的,目前我寫的 Promise 代碼中 console 并不會執(zhí)行。

          let?p2?=?new?Promise((resolve)?=>?{
          ??setTimeout(()?=>?{
          ????resolve(2);
          ??},?1000);
          });
          p2.then((value)?=>?{
          ??console.log(value);
          });
          復制代碼

          原因是執(zhí)行 .then函數(shù)的時候 Promise 狀態(tài)是 Pending ,當前我在 Promise.then方法中只寫了 狀態(tài)為 FULFILLEDREJECTED 的處理

          所以.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
          復制代碼

          正常返回 1,2,3,4 現(xiàn)在我寫的 promise 返回 1、2、4、3

          什么原因呢?原因是 .then 中的函數(shù)立即執(zhí)行了,這不符合標準呀,解決辦法是給 .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;
          ??}
          }
          復制代碼

          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);
          ????????});
          ??????});
          ????}
          ??}
          }
          復制代碼

          寫到這里,我去測試了一下顯示有 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;
          ??}
          復制代碼

          可以理解吧?每次 .then 都返回一個新的 promise 對象,.then 方法是不是就可以一直調(diào)用下去了

          這里為什么不可以直接返回 this,比如 jQuery 不就是直接返回 this 實現(xià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;
          ??}
          }
          復制代碼

          第二句

          如果 ?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;
          ??}
          復制代碼

          第三句

          如果 ?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;
          }
          復制代碼

          如果 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){

          ??}
          復制代碼

          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?#')
          ????);
          ??}
          }
          復制代碼

          判斷 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);
          ??}
          }
          復制代碼

          如果是引用數(shù)據(jù)類型,判斷數(shù)據(jù)中是否有 then 這個屬性,如果有 then 不是函數(shù),直接執(zhí)行 resolve(x)

          這里解釋一下:如果 then 是函數(shù),表示 x 可能是 Promise 對象,需要特殊處理,如果不是函數(shù),當作一般對象處理

          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);
          ??}
          }
          復制代碼

          當然,只要是代碼就有可能出現(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);
          ??}
          }
          復制代碼

          如果 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);
          ??}
          }
          復制代碼

          上述代碼基本完成了 Promise 的功能,但是還有一點規(guī)范文檔上說:
          如果 resolvePromise 和 rejectPromise 均被調(diào)用,或者被同一參數(shù)調(diào)用了多次,則優(yōu)先采用首次調(diào)用并忽略剩下的調(dià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);
          ??}
          };
          復制代碼

          結語

          雖然我想用盡量少的語言去描述或者講解這個 Promise 。但是最后依然用了將近4000字描述這個東西是什么。作者目前水平有限,只得盡量將 Promise 描述清楚。如有任何意見和建議歡迎評論區(qū)留言討論。

          關于本文

          作者:北斗落凡塵

          https://juejin.cn/post/7065693195799265287


          往期推薦


          86張腦圖,一口氣看完 React
          來分享面經(jīng)了,4年經(jīng)驗的前端在上海金三銀四遨游。
          收藏!史上最全 Vue 前端代碼風格指南

          最后


          • 歡迎加我微信,拉你進技術群,長期交流學習...

          • 歡迎關注「前端Q」,認真學前端,做個專業(yè)的技術人...

          點個在看支持我吧
          瀏覽 23
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  很很鲁很很爽 | 国产精品久久久久久久久久浪潮 | 日本亚洲无免费码在线 | www日逼com | 我要看一级黄片 |