<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>

          手寫Promise最簡20行版本,實現(xiàn)異步鏈?zhǔn)秸{(diào)用。(重構(gòu)版)

          共 4286字,需瀏覽 9分鐘

           ·

          2020-07-28 12:30

          前言

          在面試的時候,經(jīng)常會有面試官讓你實現(xiàn)一個 Promise,如果參照 A+規(guī)范來實現(xiàn)的話,可能面到天黑都結(jié)束不了。

          說到 Promise,我們首先想到的最核心的功能就是異步鏈?zhǔn)秸{(diào)用,本篇文章就帶你用 20 行代碼實現(xiàn)一個可以異步鏈?zhǔn)秸{(diào)用的 Promise。

          這個 Promise 的實現(xiàn)不考慮任何異常情況,只考慮代碼最簡短,從而便于讀者理解核心的異步鏈?zhǔn)秸{(diào)用原理。

          代碼

          先給代碼吧,真就 20 行。

          function?Promise(fn)?{
          ??this.cbs?=?[];

          ??const?resolve?=?(value)?=>?{
          ????setTimeout(()?=>?{
          ??????this.data?=?value;
          ??????this.cbs.forEach((cb)?=>?cb(value));
          ????});
          ??}

          ??fn(resolve.bind(this));
          }

          Promise.prototype.then?=?function?(onResolved)?{
          ??return?new?Promise((resolve)?=>?{
          ????this.cbs.push(()?=>?{
          ??????const?res?=?onResolved(this.data);
          ??????if?(res?instanceof?Promise)?{
          ????????res.then(resolve);
          ??????}?else?{
          ????????resolve(res);
          ??????}
          ????});
          ??});
          };

          核心案例

          new?Promise((resolve)?=>?{
          ??setTimeout(()?=>?{
          ????resolve(1);
          ??},?500);
          })
          ??.then((res)?=>?{
          ????console.log(res);
          ????return?new?Promise((resolve)?=>?{
          ??????setTimeout(()?=>?{
          ????????resolve(2);
          ??????},?500);
          ????});
          ??})
          ??.then(console.log);

          本文將圍繞這個最核心的案例來講,這段代碼的表現(xiàn)如下:

          1. 500ms 后輸出 1
          2. 500ms 后輸出 2

          實現(xiàn)

          構(gòu)造函數(shù)

          首先來實現(xiàn) Promise 構(gòu)造函數(shù)

          function?Promise(fn)?{
          ??//?Promise?resolve時的回調(diào)函數(shù)集
          ??this.cbs?=?[];

          ??//?傳遞給Promise處理函數(shù)的resolve
          ??//?這里直接往實例上掛個data
          ??//?然后把onResolvedCallback數(shù)組里的函數(shù)依次執(zhí)行一遍就可以
          ??const?resolve?=?(value)?=>?{
          ????//?注意promise的then函數(shù)需要異步執(zhí)行
          ????setTimeout(()?=>?{
          ??????this.data?=?value;
          ??????this.cbs.forEach((cb)?=>?cb(value));
          ????});
          ??}

          ??//?執(zhí)行用戶傳入的函數(shù)?
          ??//?并且把resolve方法交給用戶執(zhí)行
          ??fn(resolve.bind(this));
          }

          好,寫到這里先回過頭來看案例

          const?fn?=?(resolve)?=>?{
          ??setTimeout(()?=>?{
          ????resolve(1);
          ??},?500);
          };

          new?Promise(fn);

          分開來看,fn?就是用戶傳的函數(shù),這個函數(shù)內(nèi)部調(diào)用了?resolve?函數(shù)后,就會把?promise?實例上的?cbs?全部執(zhí)行一遍。

          到此為止我們還不知道?cbs?這個數(shù)組里的函數(shù)是從哪里來的,接著往下看。

          then

          這里是最重要的 then 實現(xiàn),鏈?zhǔn)秸{(diào)用全靠它:

          Promise.prototype.then?=?function?(onResolved)?{
          ??//?這里叫做promise2
          ??return?new?Promise((resolve)?=>?{
          ????this.cbs.push(()?=>?{
          ??????const?res?=?onResolved(this.data);
          ??????if?(res?instanceof?Promise)?{
          ????????//?resolve的權(quán)力被交給了user?promise
          ????????res.then(resolve);
          ??????}?else?{
          ????????//?如果是普通值?就直接resolve
          ????????//?依次執(zhí)行cbs里的函數(shù)?并且把值傳遞給cbs
          ????????resolve(res);
          ??????}
          ????});
          ??});
          };

          再回到案例里

          const?fn?=?(resolve)?=>?{
          ??setTimeout(()?=>?{
          ????resolve(1);
          ??},?500);
          };

          const?promise1?=?new?Promise(fn);

          promise1.then((res)?=>?{
          ??console.log(res);
          ??//?user?promise
          ??return?new?Promise((resolve)?=>?{
          ????setTimeout(()?=>?{
          ??????resolve(2);
          ????},?500);
          ??});
          });

          注意這里的命名:

          1. 我們把?new Promise?返回的實例叫做promise1

          2. 在?Promise.prototype.then?的實現(xiàn)中,我們構(gòu)造了一個新的 promise 返回,叫它promise2

          3. 在用戶調(diào)用?then?方法的時候,用戶手動構(gòu)造了一個 promise 并且返回,用來做異步的操作,叫它user promise

          那么在?then?的實現(xiàn)中,內(nèi)部的 this 其實就指向promise1

          promise2的傳入的fn?函數(shù)執(zhí)行了一個?this.cbs.push(),其實是往?promise1?的cbs數(shù)組中 push 了一個函數(shù),等待后續(xù)執(zhí)行。

          Promise.prototype.then?=?function?(onResolved)?{
          ??//?這里叫做promise2
          ??return?new?Promise((resolve)?=>?{
          ????//?這里的this其實是promise1
          ????this.cbs.push(()?=>?{});
          ??});
          };

          那么重點看這個 push 的函數(shù),注意,這個函數(shù)在?promise1?被 resolve 了以后才會執(zhí)行。

          //?promise2
          return?new?Promise((resolve)?=>?{
          ??this.cbs.push(()?=>?{
          ????//?onResolved就對應(yīng)then傳入的函數(shù)
          ????const?res?=?onResolved(this.data)
          ????//?例子中的情況?用戶自己返回了一個user?promise
          ????if?(res?instanceof?Promise)?{
          ??????//?user?promise的情況
          ??????//?用戶會自己決定何時resolve?promise2
          ??????//?只有promise2被resolve以后
          ??????//?then下面的鏈?zhǔn)秸{(diào)用函數(shù)才會繼續(xù)執(zhí)行
          ??????res.then(resolve)
          ????}?else?{
          ??????resolve(res)
          ????}
          ??})
          })

          如果用戶傳入給 then 的 onResolved 方法返回的是個?user promise,那么這個user promise里用戶會自己去在合適的時機?resolve promise2,那么進而這里的?res.then(resolve)?中的 resolve 就會被執(zhí)行:

          if?(res?instanceof?Promise)?{
          ????res.then(resolve)
          }

          結(jié)合下面這個例子來看:

          new?Promise((resolve)?=>?{
          ??setTimeout(()?=>?{
          ????//?resolve1
          ????resolve(1);
          ??},?500);
          })
          ??//?then1
          ??.then((res)?=>?{
          ????console.log(res);
          ????//?user?promise
          ????return?new?Promise((resolve)?=>?{
          ??????setTimeout(()?=>?{
          ????????//?resolve2
          ????????resolve(2);
          ??????},?500);
          ????});
          ??})
          ??//?then2
          ??.then(console.log);

          then1這一整塊其實返回的是?promise2,那么?then2?其實本質(zhì)上是?promise2.then(console.log)

          也就是說?then2注冊的回調(diào)函數(shù),其實進入了promise2的?cbs?回調(diào)數(shù)組里,又因為我們剛剛知道,resolve2?調(diào)用了之后,user promise?會被 resolve,進而觸發(fā)?promise2?被 resolve,進而?promise2?里的?cbs?數(shù)組被依次觸發(fā)。

          這樣就實現(xiàn)了用戶自己寫的?resolve2?執(zhí)行完畢后,then2?里的邏輯才會繼續(xù)執(zhí)行,也就是異步鏈?zhǔn)秸{(diào)用。

          文章總結(jié)

          本文只是簡單實現(xiàn)一個可以異步鏈?zhǔn)秸{(diào)用的 promise,而真正的 promise 比它復(fù)雜很多很多,涉及到各種異常情況、邊界情況的處理。

          promise A+規(guī)范還是值得每一個合格的前端開發(fā)去閱讀的。

          希望這篇文章可以對你有所幫助!



          ?? 看完三件事

          如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:


          1. 點個「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點在看,都是耍流氓 -_-)

          2. 關(guān)注我的官網(wǎng)?https://muyiy.cn,讓我們成為長期關(guān)系

          3. 關(guān)注公眾號「高級前端進階」,公眾號后臺回復(fù)「面試題」 送你高級前端面試題,回復(fù)「加群」加入面試互助交流群


          》》面試官都在用的題庫,快來看看《《

          瀏覽 37
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  伊人99re | 青草福利在线视频 | 日本做爱视频 | 麻豆成人精品av 麻豆精品无码视频 | 一区性感在线观看 |