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

          實(shí)現(xiàn)一個(gè)符合 Promise/A+規(guī)范的 Promise(typescript 版)

          共 30357字,需瀏覽 61分鐘

           ·

          2021-01-13 19:59

          (給前端大學(xué)加星標(biāo),提升前端技能.

          轉(zhuǎn)自:Col0ring

          juejin.cn/post/6886360224308035598

          寫(xiě)在前面

          沒(méi)錯(cuò),這又是一篇關(guān)于手寫(xiě) Promise 的文章,想必大家已經(jīng)看過(guò)很多相關(guān) Promise 的文章,關(guān)于一些 Promise 出現(xiàn)原因等問(wèn)題我就不詳細(xì)說(shuō)了,網(wǎng)上有很多資料。這次我們使用 typescript,從 ES6 中的 Promise 類(lèi)型定義入手,分析 Promise 及相關(guān)方法的傳入?yún)?shù)和返回值,手寫(xiě)一個(gè) typescript 版本的 Promise。

          Promise/A+ 規(guī)范

          Promise/A+ 規(guī)范是業(yè)內(nèi)所有的 Promise 類(lèi)庫(kù)的統(tǒng)一規(guī)范,我們要寫(xiě)的 Promise 也要符合這一規(guī)范(英文文檔請(qǐng)查看 Promises/A+:https://promisesaplus.com/,相關(guān)中文翻譯 Promise A+ 規(guī)范:http://malcolmyu.github.io/malnote/2015/06/12/Promises-A-Plus/,感謝譯者)。

          由于內(nèi)容過(guò)多,在下面的編碼中會(huì)一一進(jìn)行實(shí)現(xiàn),這里先提出幾個(gè)術(shù)語(yǔ):

          • 解決(fulfill):指一個(gè) promise 成功時(shí)進(jìn)行的一系列操作,如狀態(tài)的改變、回調(diào)的執(zhí)行。雖然規(guī)范中用 fulfill 來(lái)表示解決,但在后世的 promise 實(shí)現(xiàn)多以 resolve 來(lái)指代之。
          • 拒絕(reject):指一個(gè) promise 失敗時(shí)進(jìn)行的一系列操作。
          • 終值(eventual value):所謂終值,指的是 promise 被解決(fulfill)時(shí)傳遞給解決回調(diào)的值,由于 promise 有一次性的特征,因此當(dāng)這個(gè)值被傳遞時(shí),標(biāo)志著 promise 等待態(tài)的結(jié)束,故稱(chēng)之終值,有時(shí)也直接簡(jiǎn)稱(chēng)為值(value)。
          • 據(jù)因(reason):也就是拒絕原因,指在 promise 被拒絕(reject) 時(shí)傳遞給拒絕回調(diào)的值。

          值得注意的是,核心的 Promises/A+ 規(guī)范不設(shè)計(jì)如何創(chuàng)建、解決和拒絕 promise,而是專(zhuān)注于提供一個(gè)通用的 then 方法。所以,完成了對(duì)于then方法的交互,其實(shí)也就基本完成了對(duì)于 Promises/A+ 規(guī)范的實(shí)現(xiàn)。

          實(shí)現(xiàn) Promise

          基本功能

          首先我們要實(shí)現(xiàn) Promise 的基本功能,傳入生成器,reslovereject函數(shù)的執(zhí)行以及調(diào)用then函數(shù)對(duì)于值的基本獲取,先來(lái)看看構(gòu)造函數(shù)的類(lèi)型定義:

          //?這是類(lèi)本身,還有?all,?race?等方法在這里面定義
          interface?PromiseConstructor?{
          ????/**
          ?????*?A?reference?to?the?prototype.
          ?????*/

          ????readonly?prototype:?Promise<any>;
          ????/**
          ?????*?Creates?a?new?Promise.
          ?????*?@param?executor?A?callback?used?to?initialize?the?promise.?This?callback?is?passed?two?arguments:
          ?????*?a?resolve?callback?used?to?resolve?the?promise?with?a?value?or?the?result?of?another?promise,
          ?????*?and?a?reject?callback?used?to?reject?the?promise?with?a?provided?reason?or?error.
          ?????*/

          ???//?這里就是重點(diǎn)部分了
          ????new?(executor:?(resolve:?(value?:?T?|?PromiseLike)?=>?void,?reject:?(reason?:?any)?=>?void)?=>?void):?Promise<T>;
          ??//?...
          }

          上面我們會(huì)看到兩個(gè)其余的接口類(lèi)型,分別是PromisePromiseLike,其中Promise就是實(shí)例對(duì)象的相關(guān)屬性接口:

          //?這時(shí)實(shí)例對(duì)象,下面只是?ES2015?的接口屬性,因?yàn)楹罄m(xù)?Promise?做過(guò)更新,后續(xù)會(huì)說(shuō)明更多實(shí)例屬性
          interface?Promise?{
          ????/**
          ?????*?Attaches?callbacks?for?the?resolution?and/or?rejection?of?the?Promise.
          ?????*?@param?onfulfilled?The?callback?to?execute?when?the?Promise?is?resolved.
          ?????*?@param?onrejected?The?callback?to?execute?when?the?Promise?is?rejected.
          ?????*?@returns?A?Promise?for?the?completion?of?which?ever?callback?is?executed.
          ?????*/

          ????then(onfulfilled?:?((value:?T)?=>?TResult1?|?PromiseLike)?|?undefined?|?null,?onrejected?:?((reason:?any)?=>?TResult2?|?PromiseLike)?|?undefined?|?null):?Promise<TResult1?|?TResult2>;
          ????//...
          }

          PromiseLike的接口在下面:

          interface?PromiseLike?{
          ????/**
          ?????*?Attaches?callbacks?for?the?resolution?and/or?rejection?of?the?Promise.
          ?????*?@param?onfulfilled?The?callback?to?execute?when?the?Promise?is?resolved.
          ?????*?@param?onrejected?The?callback?to?execute?when?the?Promise?is?rejected.
          ?????*?@returns?A?Promise?for?the?completion?of?which?ever?callback?is?executed.
          ?????*/

          ????then(onfulfilled?:?((value:?T)?=>?TResult1?|?PromiseLike)?|?undefined?|?null,?onrejected?:?((reason:?any)?=>?TResult2?|?PromiseLike)?|?undefined?|?null):?PromiseLike<TResult1?|?TResult2>;
          }

          可以看出PromiseLike接口定義的就是一個(gè)擁有then()方法的對(duì)象(官方的叫法是 thenable),只要有then()方法就會(huì)將其當(dāng)做一個(gè)Promise實(shí)例看待。

          //?試驗(yàn)一下
          new?Promise((resolve)?=>?{
          ??resolve({
          ????prop:?'common?property',
          ????//?這里我們自己構(gòu)造了個(gè)?then?方法,Promise?會(huì)自動(dòng)為?then?方法?reslove?和?reject?函數(shù)
          ????then(reslove2:?any)?{
          ??????reslove2('promiselike')
          ????}
          ??})
          }).then((res)?=>?{
          ??//?果然,被當(dāng)做成了?Promise
          ??console.log(res)?//?promiselike
          })

          需要注意的是,Promise 內(nèi)部的回調(diào)函數(shù)的異步執(zhí)行機(jī)制是使用的微任務(wù),而我們所使用的環(huán)境中并沒(méi)有為我們提供微任務(wù)的相關(guān) api,所以代碼中都是使用setTimeout進(jìn)行異步模擬,將回調(diào)直接推入到事件環(huán)的最后。

          如果對(duì)事件環(huán)與微任務(wù)不太了解,可以查看下這篇文章 徹底搞懂 JS 事件輪詢(xún):https://juejin.im/post/6844904198581010439。

          下面是代碼實(shí)現(xiàn):

          //?創(chuàng)建一枚舉類(lèi)型保存響應(yīng)狀態(tài)的變量
          enum?Status?{
          ??PENDING?=?'pending',
          ??FULFILLED?=?'fulfilled',
          ??REJECTED?=?'rejected'
          }

          //?將需要類(lèi)型提出來(lái)
          type?Resolve?=?(value:?T?|?PromiseLike)?=>?void
          type?Reject?=?(reason?:?any)?=>?void
          type?Executor?=?(resolve:?Resolve,?reject:?Reject)?=>?void
          type?onFulfilled?=
          ??|?((value:?T)?=>?TResult1?|?PromiseLike)
          ??|?undefined
          ??|?null
          type?onRejected<TResult2>?=
          ??|?((reason:?any)?=>?TResult2?|?PromiseLike)
          ??|?undefined
          ??|?null


          /*?
          ?將判斷是否為?thenable?單獨(dú)提出來(lái),減少代碼冗余,不然每次都需要使用:
          ?((typeof?value?===?'object'?&&?value?!==?null)?||
          ??????typeof?value?===?'function'
          )?&&?typeof?(value?as?PromiseLike).then?===?'function'
          ??來(lái)進(jìn)行判斷,同時(shí)也有更好的?typescript?提示
          */
          function?isPromise(value:?any):?value?is?PromiseLike<any>?{
          ??return?(
          ????((typeof?value?===?'object'?&&?value?!==?null)?||
          ??????typeof?value?===?'function'
          )?&&
          ????typeof?value.then?===?'function'
          ??
          )
          }


          class?MyPromise<T>?{
          ??//?剛開(kāi)始的狀態(tài)
          ??status:?Status?=?Status.PENDING
          ??//?保存當(dāng)前?Promise?的終值,這里讓它一定會(huì)有值
          ??private?value!:?T
          ??//?保存當(dāng)前?Promise?的據(jù)因
          ??private?reason?:?any
          ??private?onFulfilledCallback:?(()?=>?void)[]?=?[]?//成功的回調(diào)
          ??private?onRejectedCallback:?(()?=>?void)[]?=?[]?//失敗的回調(diào)

          ??constructor(executor:?Executor)?{
          ????try?{
          ??????//?防止?this?丟失
          ??????executor(this._resolve.bind(this),?this._reject.bind(this))
          ????}?catch?(e)?{
          ??????//?出錯(cuò)直接?reject
          ??????this._reject(e)
          ????}
          ??}
          ??private?_resolve(value:?T?|?PromiseLike)?{
          ????try{
          ??????//?模擬微任務(wù)異步
          ??????setTimeout(()?=>?{
          ????????//?判斷是否是個(gè)?thenable?對(duì)象,如果是,我們直接取?pending?結(jié)束后的值
          ????????if?(isPromise(value))?{
          ??????????//?再次將內(nèi)部的?resolve?和?reject?函數(shù)傳入
          ??????????value.then(this._resolve.bind(this),?this._reject.bind(this))
          ??????????return
          ????????}

          ????????//?如果是?pending?狀態(tài)就變?yōu)?fulfilled
          ????????if?(this.status?===?Status.PENDING)?{
          ??????????this.status?=?Status.FULFILLED
          ??????????//?這里的?value?類(lèi)型只會(huì)是?T
          ??????????this.value?=?value
          ??????????//?resolve?后執(zhí)行?.then?時(shí)傳入的回調(diào)
          ??????????this.onFulfilledCallback.forEach((fn)?=>?fn())
          ????????}
          ??????}
          )
          ????}catch(err){
          ??????//?捕獲如果傳入的是?Promise?時(shí)在內(nèi)部拋出錯(cuò)誤后的捕獲
          ??????this._reject(err)
          ????}
          ??}

          ??//?內(nèi)部的?reject?函數(shù),就是我們實(shí)例?Promise?傳入給用戶(hù)調(diào)用的?reject
          ??private?_reject(reason:?any)?{
          ????//?大體用法同上,這里不用進(jìn)行值穿透,所以不用判斷是否為?Promise?對(duì)象了
          ????setTimeout(()?=>?{
          ??????if?(this.status?===?Status.PENDING)?{
          ????????this.status?=?Status.REJECTED
          ????????this.reason?=?reason
          ????????this.onRejectedCallback.forEach((fn)?=>?fn())
          ??????}
          ????}
          )
          ??}

          ??public?then<TResult1?=?T,?TResult2?=?never>(
          ????onfulfilled?:?onFulfilled,
          ????onrejected?:?onRejected
          ??
          ):?MyPromise<TResult1?|?TResult2>?{
          ????//??關(guān)于?onfulfilled?與?onrejected?如果沒(méi)有傳我們需要進(jìn)行值的透?jìng)?,但是在基本功能的?shí)現(xiàn)中我們先不管這個(gè)問(wèn)題,默認(rèn)一定會(huì)傳入函數(shù)
          ????//?判斷當(dāng)前狀態(tài),如果是異步?reslove?或?reject,那么此時(shí)的?status?還是?pending
          ????if?(this.status?===?Status.FULFILLED)?{
          ??????setTimeout(()?=>?{
          ????????onfulfilled!(this.value)
          ??????}
          )
          ????}
          ????if?(this.status?===?Status.REJECTED)?{
          ??????setTimeout(()?=>?{
          ????????onrejected!(this.reason)
          ??????}
          )
          ????}
          ????if?(this.status?===?Status.PENDING)?{
          ??????//?如果為?pending,需要將?onFulfilled?和?onRejected?函數(shù)都存放起來(lái),狀態(tài)確定后再依次執(zhí)行
          ??????//?執(zhí)行回調(diào)的時(shí)候有?setTimeout,這里就不加了
          ??????this.onFulfilledCallback.push(()?=>?{
          ????????onfulfilled!(this.value)
          ??????}
          )
          ??????this.onRejectedCallback.push(()?=>?{
          ????????onrejected!(this.reason)
          ??????}
          )
          ????}
          ????//?鏈?zhǔn)秸{(diào)用,這段代碼現(xiàn)在可以直接無(wú)視,為了不讓?ts?類(lèi)型報(bào)錯(cuò)加的,因?yàn)?.then?返回一個(gè)的?Promise?的值是依賴(lài)上一個(gè)?Promise?的狀態(tài)和結(jié)果的
          ????return?new?MyPromise(()?=>?{})
          ??}
          }

          OK,上面已經(jīng)完成了一個(gè)只有一條鏈的 Promise,下面做一下測(cè)試:

          //?同步
          new?MyPromise((reslove,?reject)?=>?{
          ??reslove('success')
          }).then(
          ??(res)?=>?{
          ????console.log(res)?//?success
          ??},
          ??(err)?=>?{
          ????console.log(err)
          ??}
          )

          //?異步
          new?MyPromise((reslove,?reject)?=>?{
          ??setTimeout(()?=>?{
          ????reslove('timeout?success')
          ??},?2000)
          }).then(
          ??(res)?=>?{
          ????console.log(res)?//?timeout?success
          ??},
          ??(err)?=>?{
          ????console.log(err)
          ??}
          )

          結(jié)果為立刻打印success,兩秒后打印timeout success,符合我們的預(yù)期。

          then 的深入(重點(diǎn))

          就如前面所說(shuō),Promise/A+ 規(guī)范的整個(gè)核心都在于對(duì)于then方法的處理。并且還有第三方測(cè)試庫(kù) promises-aplus-tests:https://github.com/promises-aplus/promises-tests 測(cè)試我們所寫(xiě)的 Promise 是否符合規(guī)范,我們后面也會(huì)用使用這個(gè)測(cè)試庫(kù)進(jìn)行測(cè)試。

          鏈?zhǔn)秸{(diào)用

          要實(shí)現(xiàn)then的鏈?zhǔn)秸{(diào)用,需要返回一個(gè)新的 Promise,同時(shí)不管在then中回調(diào)函數(shù)onfulfilledonrejected返回了什么值,都可以在這個(gè)新的 Promise 的then方法的回調(diào)函數(shù)參數(shù)中得到。

          我們用x來(lái)作為then方法中傳入的onfulfilledonrejected的返回值,用promise來(lái)表示then方法返回的那個(gè)新的 Promise,依據(jù) Promise/A+ 規(guī)范,我們應(yīng)該對(duì)這段解決過(guò)程 [[Resolve]](promise, x) 做如下操作:

          • xpromise 相等:如果 promisex 指向同一對(duì)象,以 TypeError 為據(jù)因拒絕執(zhí)行 promise。
          • x 為 Promise:如果 x 為 Promise ,則使 promise 接受 x 的狀態(tài)。
            • 如果 x 處于等待態(tài), promise 需保持為等待態(tài)直至 x 被執(zhí)行或拒絕
            • 如果 x 處于執(zhí)行態(tài),用相同的值執(zhí)行 promise
            • 如果 x 處于拒絕態(tài),用相同的據(jù)因拒絕 promise
          • x 為對(duì)象或函數(shù)
            • 如果 x 為對(duì)象或者函數(shù):1. ?把 x.then 賦值給 then2. ?如果取 x.then 的值時(shí)拋出錯(cuò)誤 e ,則以 e 為據(jù)因拒絕 promise3. ?如果then是函數(shù),將x作為函數(shù)的作用域this調(diào)用之。傳遞兩個(gè)回調(diào)函數(shù)作為參數(shù),第一個(gè)參數(shù)叫做resolvePromise,第二個(gè)參數(shù)叫做rejectPromise
            1. 如果 resolvePromise 以值 y 為參數(shù)被調(diào)用,則運(yùn)行 [[Resolve]](promise, y)(就是繼續(xù)遞歸這段解決過(guò)程)
            2. 如果 rejectPromise 以據(jù)因 r 為參數(shù)被調(diào)用,則以據(jù)因 r 拒絕 promise
            3. 如果 resolvePromiserejectPromise 均被調(diào)用,或者被同一參數(shù)調(diào)用了多次,則優(yōu)先采用首次調(diào)用并忽略剩下的調(diào)用
          1. 如果調(diào)用then方法拋出了異常e:
          • 如果 resolvePromiserejectPromise 已經(jīng)被調(diào)用,則忽略之
          • 否則以 e 為據(jù)因拒絕 promise
            4. ?如果 then 不是函數(shù),以 x 為參數(shù)執(zhí)行 promise
          • 如果 x 不為對(duì)象或者函數(shù),以 x 為參數(shù)執(zhí)行 promise

          大體的流程圖:

          雖然上面看著有點(diǎn)多,其實(shí)大體來(lái)說(shuō)就是讓我們符合以下規(guī)則:

          • 如果 then 中的回調(diào)函數(shù)返回一個(gè)值(非 Promise 實(shí)例或是 thenable 對(duì)象)或沒(méi)有返回值(也就是返回 undefined),那么 then 返回的 Promise 將會(huì)成為接受狀態(tài),并且將返回的值作為接受狀態(tài)的回調(diào)函數(shù)(onfulfilled)的參數(shù)值。

            new?Promise<void>((reslove)?=>?{
            reslove()
            }
            )
            .then(()?=>?{
            ??return?'success'
            }
            )
            .then((res)?=>?{
            ??console.log(res)?//?success
            }
            )
            復(fù)制代碼
          • 如果 then 中的回調(diào)函數(shù)拋出一個(gè)錯(cuò)誤,那么 then 返回的 Promise 將會(huì)成為拒絕狀態(tài),并且將拋出的錯(cuò)誤作為拒絕狀態(tài)的回調(diào)函數(shù)(onrejected)的參數(shù)值。

            new?Promise<void>((reslove)?=>?{
            reslove()
            }
            )
            .then(()?=>?{
            ??throw?new?Error('error?message')
            }
            )
            .then(
            ??()?=>?{},
            ??(err)?=>?{
            ????console.log(err)?//?Error:?error?message
            ??}
            )

            循環(huán)返回 Promise 拋出錯(cuò)誤就像下面這樣 :

            const?promise2:?Promise<any>?=?new?Promise<void>((reslove)?=>?{
            reslove()
            }
            ).then(()?=>?{
            return?promise2
            }
            )

            promise2.then(()?=>?{},?console.log)?//?[TypeError:?Chaining?cycle?detected?for?promise?#<Promise>]
          • 如果 then 中的回調(diào)函數(shù)返回一個(gè)已經(jīng)是接受狀態(tài)(fulfilled)的 Promise(我們這里暫且叫做promise1),那么 then 返回的 Promise 也會(huì)成為接受狀態(tài),并且將promise1then的回調(diào)函數(shù)的參數(shù)值,作為該被返回的 Promise 的接受狀態(tài)回調(diào)函數(shù)的參數(shù)值。

            new?Promise<void>((reslove)?=>?{
            reslove()
            }
            )
            .then(()?=>?{
            ??return?Promise.reslove('success')
            }
            )
            .then((res)?=>?{
            ??console.log(res)?//?success
            }
            )
          • 如果 then 中的回調(diào)函數(shù)返回一個(gè)已經(jīng)是拒絕狀態(tài)(rejected)的 Promise(這里我們暫且叫做promise2),那么 then 返回的 Promise 也會(huì)成為拒絕狀態(tài),并且將promise2then的回調(diào)函數(shù)的參數(shù)值,作為該被返回的 Promise 的拒絕狀態(tài)回調(diào)函數(shù)的參數(shù)值。

            new?Promise<void>((reslove)?=>?{
            reslove()
            }
            )
            .then(()?=>?{
            ???return?new?Promise.reject('error?message')
            }
            )
            .then(
            ??()?=>?{},
            ??(err)?=>?{
            ????console.log(err)?//?error?message
            ??}
            )
          • 如果 then 中的回調(diào)函數(shù)返回一個(gè)未定狀態(tài)(pending)的 Promise(這里我們暫且叫做promise3),那么 then 返回 Promise 的狀態(tài)也是未定的,并且它的終態(tài)與promise3的終態(tài)相同。同時(shí)它變?yōu)榻K態(tài)時(shí)調(diào)用then的回調(diào)函數(shù)參數(shù)與promise3變?yōu)榻K態(tài)時(shí)的回調(diào)函數(shù)的參數(shù)是相同的。

            new?Promise<void>((reslove)?=>?{
            reslove()
            }
            )
            .then(()?=>?{
            ???return?new?Promise((reslove,?reject)?=>?{
            ?????setTimeout(()=>{
            ??????reslove('delay')
            ??????},?2000
            )
            ??}
            )
            }
            )
            .then(
            ??res?=>?{
            ????console.log(res)?//?兩秒后打印?delay
            ??}
            )

          好了,照著上面的解決過(guò)程 ,我們來(lái)寫(xiě)一下這個(gè)處理函數(shù):

          function?resolvePromise<T>(
          ??promise2:?MyPromise,
          ??x:?T?|?PromiseLike,
          ??resolve:?Resolve,
          ??reject:?Reject
          )?
          {
          ??//?不能引用同一個(gè)對(duì)象,不然會(huì)無(wú)限循環(huán)的
          ??if?(promise2?===?x)?{
          ????const?e?=?new?TypeError(
          ??????'TypeError:?Chaining?cycle?detected?for?promise?#'
          ????)
          ????//?清空棧信息,不太清楚為什么?Promise?要清除這個(gè),先不管了,繼續(xù)往下
          ????e.stack?=?''
          ????//?直接進(jìn)入錯(cuò)誤的回調(diào)
          ????return?reject(e)
          ??}
          ??let?called?=?false?//?防止多次調(diào)用

          ??//?如果?x?為?Promise,通過(guò)上面的知識(shí)我們知道判斷是否是個(gè)?Promise?或者像?Promise?我們是判斷一個(gè)對(duì)象是否有?then?方法,可以發(fā)現(xiàn)在下面判斷是否是對(duì)象或者函數(shù)中也有相同的判斷,所以這里我們可以直接省略

          ??//?如果?x?是對(duì)象或函數(shù)
          ??if?((typeof?x?===?'object'?&&?x?!=?null)?||?typeof?x?===?'function')?{
          ????try?{
          ??????/*?
          ??????存儲(chǔ)了一個(gè)指向 x.then 的引用,然后測(cè)試并調(diào)用該引用,以避免多次訪問(wèn) x.then 屬性。這種預(yù)防措施確保了該屬性的一致性,因?yàn)槠渲悼赡茉跈z索調(diào)用時(shí)被改變。
          ??????注:這里可以用我們封裝的判斷方法 isPromise 判斷,但是既然跟著解決過(guò)程走,那么還是老老實(shí)實(shí)操作一下吧
          ??????*/

          ??????//?手動(dòng)轉(zhuǎn)一下類(lèi)型
          ??????const?then?=?(x?as?PromiseLike).then
          ??????if?(typeof?then?===?'function')?{
          ????????//?這里其實(shí)就是調(diào)用傳入的?Promise?的?then?方法,下面代碼就是執(zhí)行了?x.then(()=>{},()=>{})
          ????????then.call(
          ??????????x,
          ??????????(y)?=>?{
          ????????????if?(called)?return
          ????????????called?=?true
          ????????????//?如果是?Promise,我們應(yīng)該遞歸地獲取到最終狀態(tài)的值,傳入相同的處理函數(shù),不論是成功還是失敗都能直接拋出到最外層
          ????????????resolvePromise(promise2,?y,?resolve,?reject)
          ??????????},
          ??????????(r)?=>?{
          ????????????if?(called)?return
          ????????????called?=?true
          ????????????//?如果傳入的?Promise?被拒絕,直接拋出到最外層
          ????????????reject(r)
          ??????????}
          ????????)
          ??????}?else?{
          ????????//?不是?Promise?對(duì)象,當(dāng)做普通值處理
          ????????resolve(x)
          ??????}
          ????}?catch?(e)?{
          ??????//?如果中間有錯(cuò)誤。直接變?yōu)榫芙^態(tài)
          ??????//?但是如果出現(xiàn)錯(cuò)誤之前已經(jīng)改變了狀態(tài),那么久不用管
          ??????if?(called)?return
          ??????called?=?true
          ??????reject(e)
          ????}
          ??}?else?{
          ????//?普通值處理
          ????resolve(x)
          ??}
          }

          可以將上面的處理過(guò)程的代碼實(shí)現(xiàn)與描述一步步帶入查看,基本上都是能吻合的。

          下面將其帶入到then中:

          class?MyPromise?{
          ??//?...
          ??public?then(
          ????onfulfilled?:?onFulfilled,
          ????onrejected?:?onRejected
          ??):?MyPromise?{
          ??????
          ????//?現(xiàn)在我們將這個(gè)新生成的?Promise?和現(xiàn)在的?Promise?相互聯(lián)系
          ????const?promise2?=?new?MyPromise((resolve,?reject)?=>?{
          ??????if?(this.status?===?Status.FULFILLED)?{
          ????????setTimeout(()?=>?{
          ??????????try?{
          ????????????//??獲取到?x,然后與要返回的?Promise?產(chǎn)生聯(lián)系
          ????????????let?x?=?onfulfilled!(this.value)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????}
          )
          ??????}
          ??????if?(this.status?===?Status.REJECTED)?{
          ????????setTimeout(()?=>?{
          ??????????try?{
          ????????????//??獲取到?x,然后與要返回的?Promise?產(chǎn)生聯(lián)系
          ????????????let?x?=?onrejected!(this.reason)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????}
          )
          ??????}
          ??????if?(this.status?===?Status.PENDING)?{
          ????????//?如果為?pending,需要將?onFulfilled?和?onRejected?函數(shù)都存放起來(lái),狀態(tài)確定后再依次執(zhí)行
          ????????//?執(zhí)行回調(diào)的時(shí)候有?setTimeout,這里就不加了
          ????????this.onFulfilledCallback.push(()?=>?{
          ??????????try?{
          ????????????let?x?=?onfulfilled!(this.value)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????}
          )
          ????????this.onRejectedCallback.push(()?=>?{
          ??????????try?{
          ????????????let?x?=?onrejected!(this.reason)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????}
          )
          ??????}
          ????}
          )
          ????return?promise2
          ??}

          ??//...
          }

          測(cè)試一下:

          new?MyPromise<void>((resolve)?=>?{
          ??resolve()
          }
          )
          ??.then(()?=>?{
          ????return?'step1'
          ??}
          )
          ??.then((res)?=>?{
          ????return?res?+?':'?+?'step2'
          ??}
          )
          ??.then((res)?=>?{
          ????console.log(res)?//?step1:step2
          ??}
          )

          很好,完美符合預(yù)期。

          值的穿透

          之前我們使用then時(shí)都是假設(shè)我們一定會(huì)向then中傳入回調(diào)函數(shù),但是事實(shí)上在 Promise/A+ 規(guī)范中兩個(gè)回調(diào)函數(shù)都是可以缺省的,這也是為什么我會(huì)在后面加上?。當(dāng)我們不向其傳入回調(diào)函數(shù)時(shí),此時(shí)就會(huì)觸發(fā)值的穿透效果。

          //?就像下面這樣
          new?Promise((reslove)?=>?{
          ??reslove('hello')
          })
          ??.then()
          ??.then()
          ??.then()
          ??.then((res)?=>?{
          ????console.log(res)?//?'hello'
          ??})

          所以我們需要改造一下我們的then函數(shù),改造方法其實(shí)非常簡(jiǎn)單:

          class?MyPromise?{
          ??//?...
          ??public?then(
          ????onfulfilled?:?onFulfilled,
          ????onrejected?:?onRejected
          ??):?MyPromise?{
          ??//?如果傳入的不是函數(shù),就進(jìn)行值的穿透,成功回調(diào)是返回相同的值,失敗的回調(diào)是直接拋出錯(cuò)誤
          ????//?注意這里不能直接給上面?zhèn)魅氲膮?shù)添加默認(rèn)值,因?yàn)樾枰袛嗍欠袷呛瘮?shù)
          ????const?onfulfilledFn?=
          ??????typeof?onfulfilled?===?'function'
          ??????????onfulfilled
          ????????:?(v:?T?|?TResult1)?=>?v?as?TResult1
          ????const?onrejectedFn?=
          ??????typeof?onrejected?===?'function'
          ??????????onrejected
          ????????:?(e:?any)?=>?{
          ????????????throw?e
          ??????????}
          ???//?將下面的?onfulfilled?改成?onfulfilledFn,onrejected?改成?onrejectedFn?就行了
          ????//?現(xiàn)在我們將這個(gè)新生成的?Promise?和現(xiàn)在的?Promise?相互聯(lián)系
          ????const?promise2?=?new?MyPromise((resolve,?reject)?=>?{
          ??????if?(this.status?===?Status.FULFILLED)?{
          ????????setTimeout(()?=>?{
          ??????????try?{
          ????????????//??獲取到?x,然后與要返回的?Promise?產(chǎn)生聯(lián)系
          ????????????let?x?=?onfulfilledFn(this.value)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????}
          )
          ??????}
          ??????if?(this.status?===?Status.REJECTED)?{
          ????????setTimeout(()?=>?{
          ??????????try?{
          ????????????//??獲取到?x,然后與要返回的?Promise?產(chǎn)生聯(lián)系
          ????????????let?x?=?onrejectedFn(this.reason)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????}
          )
          ??????}
          ??????if?(this.status?===?Status.PENDING)?{
          ????????//?如果為?pending,需要將?onFulfilled?和?onRejected?函數(shù)都存放起來(lái),狀態(tài)確定后再依次執(zhí)行
          ????????//?執(zhí)行回調(diào)的時(shí)候有?setTimeout,這里就不加了
          ????????this.onFulfilledCallback.push(()?=>?{
          ??????????try?{
          ????????????let?x?=?onfulfilledFn(this.value)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????}
          )
          ????????this.onRejectedCallback.push(()?=>?{
          ??????????try?{
          ????????????let?x?=?onrejectedFn(this.reason)
          ????????????resolvePromise(promise2,?x,?resolve,?reject)
          ??????????}?catch?(e)?{
          ????????????reject(e)
          ??????????}
          ????????}
          )
          ??????}
          ????}
          )

          ????return?promise2
          ??}

          ??//...
          }

          好了,看到了這里,恭喜你,已經(jīng)完成了 Promise 最重要的部分,后續(xù)的所有 api 基本都是圍繞著上面所寫(xiě)的部分展開(kāi)的。

          規(guī)范測(cè)試

          使用我們前面提到的測(cè)試 Promise 規(guī)范的第三方庫(kù)來(lái)進(jìn)行測(cè)試:

          npm?install?promises-aplus-tests?-D
          #?or
          yarn?add?promises-aplus-tests?-D
          復(fù)制代碼
          //?在文件末尾加上

          //?忽略?typescript?校驗(yàn)
          //?@ts-ignore
          MyPromise.defer?=?MyPromise.deferred?=?function?()?{
          ??let?dfd:?any?=?{}
          ??dfd.promise?=?new?MyPromise((resolve,?reject)?=>?{
          ????dfd.resolve?=?resolve
          ????dfd.reject?=?reject
          ??})
          ??return?dfd
          }

          export?=?MyPromise

          然后使用tsc命令將ts文件編譯,運(yùn)行npx promises-aplus-tests 編譯后的js文件位置。

          遺憾的是,我們的 Promise 并沒(méi)有通過(guò)所有的測(cè)試,但是我們可以看到這 16 個(gè)未通過(guò)測(cè)試的報(bào)錯(cuò)都相同,調(diào)用處理的回調(diào)超時(shí)(超過(guò)了 200 ms 的延時(shí)),我的個(gè)人理解是由于setTimeout這個(gè) api 不能完全模擬微任務(wù)而造成的延時(shí)效果(說(shuō)錯(cuò)了請(qǐng)大佬們輕點(diǎn)噴)。

          如果要單看測(cè)試結(jié)果來(lái)說(shuō),想全部通過(guò)測(cè)試我們可以把最開(kāi)始定義的 Promise 內(nèi)部的reslove函數(shù)做一個(gè)修改:

          class?MyPromise{
          ??private?_resolve(value:?T?|?PromiseLike)?{
          ????try{
          ??????setTimeout(()?=>?{
          ????????/*
          ?????????刪除下面這段代碼就可通過(guò)全部測(cè)試:
          ??????????if?(isPromise(value))?{
          ????????????value.then(this._resolve.bind(this),?this._reject.bind(this))
          ????????????return
          ??????????}
          ????????*/


          ????????if?(this.status?===?Status.PENDING)?{
          ??????????this.status?=?Status.FULFILLED
          ??????????this.value?=?value?as?T?//?強(qiáng)制轉(zhuǎn)換類(lèi)型
          ??????????this.onFulfilledCallback.forEach((fn)?=>?fn())
          ????????}
          ??????})
          ????}catch(err){
          ??????this._reject(err)
          ????}
          ??}
          }

          當(dāng)然,雖然通過(guò)了全部測(cè)試,但是很明顯并不是符合預(yù)期的結(jié)果,當(dāng)我們使用一個(gè)PromiseLike對(duì)象時(shí)與真實(shí)的 Promise 結(jié)果并不一致:

          //?還是用最開(kāi)始的那個(gè)例子
          new?Promise((resolve)?=>?{
          ??resolve({
          ????prop:?'common?property',
          ????then(reslove2:?any)?{
          ??????reslove2('promiselike')
          ????}
          ??})
          }).then((res)?=>?{
          ??//?真實(shí)的?Promise?這里是?promiselike
          ??console.log(res)?//?{?prop:?'common?property',?then:?[Function:?then]?}?
          })

          所以,就結(jié)果而言,也算是基本合格吧。

          Promise 的拓展方法

          在前面我們已經(jīng)完成了 Promise 的核心部分,現(xiàn)在可以依靠之前的代碼再次完善我們的 Promise。

          注: 在 Promise 的接口定義里,所有的實(shí)例方法都是定義在Promise接口中的,所有的靜態(tài)方法都是定義在PromiseConstructor接口中的。

          Promise.prototype.catch

          Promise.prototype.catch(onrejected) 方法返回一個(gè)Promise,并且處理拒絕的情況。它的行為與調(diào)用Promise.prototype.then(undefined, onRejected)相同。

          接口類(lèi)型:

          interface?Promise?{
          ????/**
          ?????*?Attaches?a?callback?for?only?the?rejection?of?the?Promise.
          ?????*?@param?onrejected?The?callback?to?execute?when?the?Promise?is?rejected.
          ?????*?@returns?A?Promise?for?the?completion?of?the?callback.
          ?????*/

          ????catch(onrejected?:?((reason:?any)?=>?TResult?|?PromiseLike)?|?undefined?|?null):?Promise<T?|?TResult>;
          }

          實(shí)現(xiàn)代碼:

          interface?MyPromise?{
          ??//?事實(shí)上它內(nèi)部就是這樣調(diào)用的
          ??public?catch(
          ????onrejected?:?onRejected
          ??):?MyPromise?{
          ????return?this.then(null,?onrejected)
          ??}
          }

          Promise.resolve

          Promise.resolve(value) 方法返回一個(gè)以給定值解析后的 Promise 對(duì)象。

          • 如果這個(gè)值是一個(gè) Promise 實(shí)例 ,那么將返回這個(gè) Promise 實(shí)例。
          • 如果這個(gè)值是thenable,會(huì)一直跟隨thenable拿到它的最終狀態(tài)。
          • 如果都不是上面的值,返回的 Promise 實(shí)例將用這個(gè)值作為成功狀態(tài)的終值。

          接口類(lèi)型:

          interface?PromiseConstructor?{
          ???//?可以看到有兩種函數(shù)體,所以我們需要進(jìn)行函數(shù)重載的定義
          ?????/**
          ?????*?Creates?a?new?resolved?promise.
          ?????*?@returns?A?resolved?promise.
          ?????*/

          ????resolve():?Promise<void>;

          ????/**
          ?????*?Creates?a?new?resolved?promise?for?the?provided?value.
          ?????*?@param?value?A?promise.
          ?????*?@returns?A?promise?whose?internal?state?matches?the?provided?promise.
          ?????*/

          ????resolve(value:?T?|?PromiseLike):?Promise;
          }

          實(shí)現(xiàn)代碼:

          interface?MyPromise?{
          ??//?函數(shù)重載
          ??static?resolve():?MyPromise<void>
          ??static?resolve(value:?T?|?PromiseLike):?MyPromise
          ??//?最后的函數(shù)實(shí)體需要同時(shí)支持上面兩種函數(shù)重載的類(lèi)型,所以我們變成可選值
          ??static?resolve(value?:?T?|?PromiseLike):?MyPromise?{
          ????//?如果是?Promise,直接返回當(dāng)前?Promise
          ????if?(value?instanceof?MyPromise)?{
          ??????return?value
          ????}
          ????return?new?MyPromise((resolve)?=>?{
          ??????//?我們?cè)趦?nèi)部已經(jīng)做了對(duì)?thenable?的處理了,所以直接?reslove
          ??????//?因?yàn)楸仨殏髦?,所以這里就強(qiáng)制推斷了
          ??????resolve(value!)
          ????})
          ??}
          }

          Promise.reject

          Promise.reject(reason) 方法返回一個(gè)帶有拒絕原因的Promise對(duì)象。

          接口類(lèi)型:

          interface?PromiseConstructor?{
          ????/**
          ?????*?Creates?a?new?rejected?promise?for?the?provided?reason.
          ?????*?@param?reason?The?reason?the?promise?was?rejected.
          ?????*?@returns?A?new?rejected?Promise.
          ?????*/

          ????reject(reason?:?any):?Promise;
          }

          實(shí)現(xiàn)代碼:

          interface?MyPromise?{
          ??static?reject(reason?:?any):?MyPromise?{
          ???//?不需要額外判斷
          ????return?new?MyPromise((resolve,?reject)?=>?{
          ??????reject(reason)
          ????})
          ??}
          }

          Promise.all

          Promise.all(iterable)方法接收一個(gè)iterable對(duì)象,返回一個(gè) Promise 實(shí)例,此實(shí)例在 iterable 參數(shù)內(nèi)所有的 thenable 狀態(tài)都為fulfilled或參數(shù)中不包含 thenable 時(shí)狀態(tài)為fulfilled,并且reslove一個(gè)包含了所有傳入thenablereslove值的數(shù)組。如果參數(shù)內(nèi)的 thenable 有一個(gè)狀態(tài)為rejected,此實(shí)例狀態(tài)也為rejected,并且reject第一個(gè)失敗 thenable 的結(jié)果。否者如果有thenable的狀態(tài)為pending,此實(shí)例的狀態(tài)也為pending

          接口定義:

          interface?PromiseConstructor?{
          ??????/**
          ?????*?Creates?a?Promise?that?is?resolved?with?an?array?of?results?when?all?of?the?provided?Promises
          ?????*?resolve,?or?rejected?when?any?Promise?is?rejected.
          ?????*?@param?values?An?array?of?Promises.
          ?????*?@returns?A?new?Promise.
          ?????*/

          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike,?T3?|?PromiseLike,?T4?|?PromiseLike,?T5?|?PromiseLike,?T6?|?PromiseLike,?T7?|?PromiseLike,?T8?|?PromiseLike,?T9?|?PromiseLike,?T10?|?PromiseLike]):?Promise<[T1,?T2,?T3,?T4,?T5,?T6,?T7,?T8,?T9,?T10]>;
          ??
          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike,?T3?|?PromiseLike,?T4?|?PromiseLike,?T5?|?PromiseLike,?T6?|?PromiseLike,?T7?|?PromiseLike,?T8?|?PromiseLike,?T9?|?PromiseLike]):?Promise<[T1,?T2,?T3,?T4,?T5,?T6,?T7,?T8,?T9]>;
          ??
          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike,?T3?|?PromiseLike,?T4?|?PromiseLike,?T5?|?PromiseLike,?T6?|?PromiseLike,?T7?|?PromiseLike,?T8?|?PromiseLike]):?Promise<[T1,?T2,?T3,?T4,?T5,?T6,?T7,?T8]>;
          ??
          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike,?T3?|?PromiseLike,?T4?|?PromiseLike,?T5?|?PromiseLike,?T6?|?PromiseLike,?T7?|?PromiseLike]):?Promise<[T1,?T2,?T3,?T4,?T5,?T6,?T7]>;
          ??
          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike,?T3?|?PromiseLike,?T4?|?PromiseLike,?T5?|?PromiseLike,?T6?|?PromiseLike]):?Promise<[T1,?T2,?T3,?T4,?T5,?T6]>;
          ??
          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike,?T3?|?PromiseLike,?T4?|?PromiseLike,?T5?|?PromiseLike]):?Promise<[T1,?T2,?T3,?T4,?T5]>;

          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike,?T3?|?PromiseLike,?T4?|?PromiseLike]):?Promise<[T1,?T2,?T3,?T4]>;
          ??
          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike,?T3?|?PromiseLike]):?Promise<[T1,?T2,?T3]>;
          ??
          ????all(values:?readonly?[T1?|?PromiseLike,?T2?|?PromiseLike]):?Promise<[T1,?T2]>;

          ????all(values:?readonly?(T?|?PromiseLike)[]):?Promise;
          ????//?看著有點(diǎn)多,其實(shí)上面都是表示傳入?yún)?shù)是一個(gè)數(shù)組的情況,這樣寫(xiě)是因?yàn)閭魅氲?Promise?中的?T?可能不同而重載不同元組類(lèi)型
          ????
          ????//?see:?lib.es2015.iterable.d.ts
          ????all(values:?Iterable>):?Promise;
          }

          在類(lèi)型定義中我們可以看到,當(dāng)我們傳入給Promise.all()一個(gè)迭代器(Iterable)的時(shí)候參數(shù)也是正確的,而數(shù)組本質(zhì)也是一個(gè)迭代器,所以我們的編碼操作可以完全圍繞著迭代器進(jìn)行展開(kāi)。

          實(shí)現(xiàn)代碼:

          interface?MyPromise?{
          ??static?all(
          ??values:?readonly?[
          ???T1?|?PromiseLike,
          ???T2?|?PromiseLike,
          ???T3?|?PromiseLike,
          ???T4?|?PromiseLike,
          ???T5?|?PromiseLike,
          ???T6?|?PromiseLike,
          ???T7?|?PromiseLike,
          ???T8?|?PromiseLike,
          ???T9?|?PromiseLike,
          ???T10?|?PromiseLike
          ???]
          ??):?MyPromise<[T1,?T2,?T3,?T4,?T5,?T6,?T7,?T8,?T9,?T10]>
          ??//?.....太占篇幅,省略了
          ??static?all(values:?Iterable>):?MyPromise
          ??//?我們這里的實(shí)際實(shí)現(xiàn)也完全按照按照迭代器來(lái)實(shí)現(xiàn)就行了
          ??static?all(values:?Iterable>):?MyPromise?{
          ????return?new?MyPromise((resolve,?reject)?=>?{
          ??????//?PromiseLike?對(duì)象會(huì)跟蹤轉(zhuǎn)換為?T
          ??????const?resultArr:?T[]?=?[]
          ??????//??判斷是否已經(jīng)全部完成了
          ??????const?doneArr:?boolean[]?=?[]
          ??????//?獲取迭代器對(duì)象
          ??????let?iter?=?values[Symbol.iterator]()
          ??????//?獲取值?{value:xxx,?done:?false}
          ??????let?cur?=?iter.next()
          ??????//?判斷迭代器是否迭代完畢同時(shí)將最后得到的值放入結(jié)果數(shù)組中
          ??????const?resolveResult?=?(value:?T,?index:?number,?done?:?boolean)?=>?{
          ????????resultArr[index]?=?value
          ????????doneArr[index]?=?true
          ????????if?(done?&&?doneArr.every((item)?=>?item))?{
          ??????????resolve(resultArr)
          ????????}
          ??????}
          ??????for?(let?i?=?0;?!cur.done;?i++)?{
          ????????const?value?=?cur.value
          ????????doneArr.push(false)
          ????????cur?=?iter.next()
          ????????if?(isPromise(value))?{
          ??????????value.then((value:?T)?=>?{
          ????????????resolveResult(value,?i,?cur.done)
          ??????????},?reject)
          ????????}?else?{
          ??????????resolveResult(value,?i,?cur.done)
          ????????}
          ??????}
          ????})
          ??}

          Promise.race

          Promise.race(iterable) 方法接收一個(gè)iterable對(duì)象,返回一個(gè) Promise,一旦迭代器中的某個(gè)thenable的狀態(tài)變?yōu)?code style="">fulfiled或rejected,該實(shí)例的狀態(tài)就會(huì)變成fulfiledrejected

          接口定義:

          interface?PromiseConstructor?{
          ????/**
          ?????*?Creates?a?Promise?that?is?resolved?or?rejected?when?any?of?the?provided?Promises?are?resolved
          ?????*?or?rejected.
          ?????*?@param?values?An?array?of?Promises.
          ?????*?@returns?A?new?Promise.
          ?????*/

          ????race(values:?readonly?T[]):?Promiseextends?PromiseLike???U?:?T>;

          ????//?see:?lib.es2015.iterable.d.ts
          ????race(values:?Iterable):?Promiseextends?PromiseLike???U?:?T>;
          }

          代碼實(shí)現(xiàn):

          class?MyPromise?{
          ??static?race(
          ????values:?Iterable
          ??):?MyPromiseextends?PromiseLike???U?:?T>
          ??static?race(
          ????values:?readonly?T[]
          ??):?MyPromiseextends?PromiseLike???U?:?T>
          ??//?還是直接使用迭代器
          ??static?race(
          ????values:?Iterable
          ??):?MyPromiseextends?PromiseLike???U?:?T>?{
          ??????return?new?MyPromise((resolve,?reject)?=>?{
          ????????const?iter?=?values[Symbol.iterator]()
          ????????let?cur?=?iter.next()
          ????????while?(!cur.done)?{
          ??????????const?value?=?cur.value
          ??????????cur?=?iter.next()
          ??????????if?(isPromise(value))?{
          ????????????value.then(resolve,?reject)
          ??????????}?else?{
          ????????????//?普通值,這時(shí)的值為?T,但是?Typescript?無(wú)法再深度判斷了,需要自己手動(dòng)轉(zhuǎn)換
          ????????????resolve(value?as?T?extends?PromiseLike???U?:?T)
          ??????????}
          ????????}
          ??????})
          ??}
          }

          Promise.prototype.finally

          ES2018提出

          Promise.prototype.finally(onfinally) 方法返回一個(gè)新的 Promise,并且該 Promise 的狀態(tài)為 Promise 鏈條中前一個(gè) Promise 的狀態(tài)。在上一個(gè) Promise 結(jié)束時(shí),無(wú)論結(jié)果狀態(tài)是fulfilled或者是rejected,都會(huì)執(zhí)行指定的回調(diào)函數(shù)。 這為在Promise是否成功完成后都需要執(zhí)行的代碼提供了一種方式。避免了同樣的語(yǔ)句需要在then()catch()中各寫(xiě)一次的情況。

          具體用法:

          //?不使用?finally
          new?Promise((resolve)?=>?{
          ???resolve()
          }).then(()?=>?{
          ??console.log('success')
          ??console.log('finally')
          })
          .catch(()?=>?{
          ??console.log('error')
          ??console.log('finally')
          })

          //?使用?finally
          new?Promise((resolve)?=>?{
          ???resolve()
          }).then(()?=>?{
          ??console.log('success')
          })
          .catch(()?=>?{
          ??console.log('error')
          })
          .finally(()?=>?{
          ????console.log('finally')
          })

          接口定義:

          interface?Promise?{
          ??????/**
          ?????*?Attaches?a?callback?that?is?invoked?when?the?Promise?is?settled?(fulfilled?or?rejected).?The
          ?????*?resolved?value?cannot?be?modified?from?the?callback.
          ?????*?@param?onfinally?The?callback?to?execute?when?the?Promise?is?settled?(fulfilled?or?rejected).
          ?????*?@returns?A?Promise?for?the?completion?of?the?callback.
          ?????*/

          ????finally(onfinally?:?(()?=>?void)?|?undefined?|?null):?Promise<T>
          }

          代碼實(shí)現(xiàn):

          class?MyPromise?{
          ??//?無(wú)論如何都會(huì)執(zhí)行
          ??public?finally(onfinally?:?onFinally):?MyPromise?{
          ????return?this.then(
          ??????(value)?=>
          ????????MyPromise.resolve(
          ?????//?如果?onfinally?返回的是一個(gè)?thenable?也會(huì)等返回的?thenable?狀態(tài)改變才會(huì)進(jìn)行后續(xù)的?Promise
          ??????????typeof?onfinally?===?'function'???onfinally()?:?onfinally
          ????????).then(()?=>?value),
          ??????(reason)?=>
          ????????MyPromise.resolve(
          ??????????typeof?onfinally?===?'function'???onfinally()?:?onfinally
          ????????).then(()?=>?{
          ??????????throw?reason
          ????????})
          ????)
          ??}
          }

          Promise.allSettled

          ES2020提出

          Promise.allSettled(iterable)方法接收一個(gè)iterable對(duì)象,返回一個(gè) Promise 實(shí)例,該實(shí)例的狀態(tài)總是fulfilledpending。在 iterable 參數(shù)內(nèi)所有的 thenable 狀態(tài)不論為fullfilled還是rejected,reslovereject的值都會(huì)被包裝成一個(gè)對(duì)象保留,當(dāng)所有的thenable執(zhí)行完畢后該 Promise 實(shí)例會(huì)reslove一個(gè)包含了這些所有對(duì)象的數(shù)組。如果有thenable的狀態(tài)為pending,此實(shí)例的狀態(tài)也為pending。

          具體用法:

          const?promise1?=?new?Promise((resolve)?=>?{
          ??resolve(1)
          })

          const?promise2?=?new?Promise((resolve)?=>?{
          ??resolve(2)
          })
          const?promise3?=?new?Promise((resolve,?reject)?=>?{
          ??reject(3)
          })

          Promise.allSettled([promise1,?promise2,?promise3]).then(console.log)
          /*
          打印結(jié)果為:
          [
          ??{?status:?'fulfilled',?value:?1?},
          ??{?status:?'fulfilled',?value:?2?},
          ??{?status:?'rejected',?reason:?3?}
          ]
          */

          接口定義:

          interface?PromiseConstructor?{
          ??/**
          ?????*?Creates?a?Promise?that?is?resolved?with?an?array?of?results?when?all
          ?????*?of?the?provided?Promises?resolve?or?reject.
          ?????*?@param?values?An?array?of?Promises.
          ?????*?@returns?A?new?Promise.
          ?????*/

          ????allSettledextends?readonly?unknown[]?|?readonly?[unknown]>(values:?T):
          ????????Promise<{?-readonly?[P?in?keyof?T]:?PromiseSettledResultextends?PromiseLike???U?:?T[P]>?}>;

          ????/**
          ?????*?Creates?a?Promise?that?is?resolved?with?an?array?of?results?when?all
          ?????*?of?the?provided?Promises?resolve?or?reject.
          ?????*?@param?values?An?array?of?Promises.
          ?????*?@returns?A?new?Promise.
          ?????*/

          ????allSettled(values:?Iterable):?Promiseextends?PromiseLike???U?:?T>[]>;
          }

          代碼實(shí)現(xiàn):

          class?MyPromise?{
          ??static?allSettledextends?readonly?unknown[]?|?readonly?[unknown]>(
          ????values:?T
          ??):?MyPromise<
          ????{
          ??????-readonly?[P?in?keyof?T]:?PromiseSettledResult<
          ????????T[P]?extends?PromiseLike???U?:?T[P]
          ??????>
          ????}
          ??>
          ??static?allSettled(
          ????values:?Iterable
          ??):?MyPromiseextends?PromiseLike???U?:?T>[]>
          ??//?重載函數(shù)的返回值有沖突,想不報(bào)錯(cuò)需要使用聯(lián)合類(lèi)型,這邊圖省事直接用?any?了
          ??static?allSettled(values:?Iterable):?MyPromise<any>?{
          ????//?大體寫(xiě)法參照?Promise.all()
          ????return?new?MyPromise((reslove)?=>?{
          ??????const?resultArr:?any[]?=?[]
          ??????const?doneArr:?boolean[]?=?[]
          ??????//?獲取迭代器
          ??????const?iter?=?values[Symbol.iterator]()
          ??????//?當(dāng)前值
          ??????let?cur?=?iter.next()
          ??????const?resolveResult?=?(value:?any,?index:?number,?done?:?boolean)?=>?{
          ????????resultArr[index]?=?{
          ??????????status:?Status.FULFILLED,
          ??????????value
          ????????}
          ????????doneArr[index]?=?true
          ????????if?(done?&&?doneArr.every((item)?=>?item))?{
          ??????????reslove(resultArr)
          ????????}
          ??????}
          ??????for?(let?i?=?0;?!cur.done;?i++)?{
          ????????const?value?=?cur.value
          ????????doneArr.push(false)
          ????????cur?=?iter.next()
          ????????if?(isPromise(value))?{
          ??????????value.then(
          ????????????(value)?=>?{
          ??????????????resolveResult(value,?i,?cur.done)
          ????????????},
          ????????????(reason)?=>?{
          ??????????????//?這里和?resolve?基本也沒(méi)什么區(qū)別,修改一下?tīng)顟B(tài)和屬性就ok了
          ??????????????resultArr[i]?=?{
          ????????????????status:?Status.REJECTED,
          ????????????????reason
          ??????????????}
          ??????????????doneArr[i]?=?true
          ??????????????if?(cur.done?&&?doneArr.every((item)?=>?item))?{
          ????????????????reslove(resultArr)
          ??????????????}
          ????????????}
          ??????????)
          ??????????//?不是?thenable?直接存儲(chǔ)
          ????????}?else?{
          ??????????resolveResult(value,?i,?cur.done)
          ????????}
          ??????}
          ????})
          ??}
          }

          Promise.any

          ESNEXT提出,還處于實(shí)驗(yàn)版本,只有少部分瀏覽器支持

          Promise.any(iterable) 方法接收一個(gè) iterable 對(duì)象,返回一個(gè) Promise 實(shí)例。只要iterable中的一個(gè) thenable 的狀態(tài)為fulfilled,就返回那個(gè)thenablereslove的值,并且該實(shí)例的狀態(tài)也為fulfilled。如果iterable中全為thenable并且狀態(tài)全部為rejected,該實(shí)例的狀態(tài)也為rejected并且reject一個(gè)AggregateError類(lèi)型的實(shí)例(它是 Error 的一個(gè)子類(lèi),用于把單一的錯(cuò)誤集合在一起,目前還在實(shí)驗(yàn)階段,只有少部分瀏覽器支持)。本質(zhì)上,這個(gè)方法和Promise.all()是相反的。

          具體用法:

          const?pErr?=?new?Promise((resolve,?reject)?=>?{
          ??reject("總是失敗");
          });

          const?pSlow?=?new?Promise((resolve,?reject)?=>?{
          ??setTimeout(resolve,?500,?"最終完成");
          });

          const?pFast?=?new?Promise((resolve,?reject)?=>?{
          ??setTimeout(resolve,?100,?"很快完成");
          });

          Promise.any([pErr,?pSlow,?pFast]).then((value)?=>?{
          ??console.log(value);
          ??//?pFast?fulfils?first
          })
          //?打印結(jié)果為:?"很快完成"

          接口定義:

          interface?PromiseConstructor?{
          ???/**
          ?????*?The?any?function?returns?a?promise?that?is?fulfilled?by?the?first?given?promise?to?be?fulfilled,?or?rejected?with?an?AggregateError?containing?an?array?of?rejection?reasons?if?all?of?the?given?promises?are?rejected.?It?resolves?all?elements?of?the?passed?iterable?to?promises?as?it?runs?this?algorithm.
          ?????*?@param?values?An?array?or?iterable?of?Promises.
          ?????*?@returns?A?new?Promise.
          ?????*/

          ??any(values:?(T?|?PromiseLike)[]?|?Iterable>):?Promise
          }

          代碼實(shí)現(xiàn):

          class?MyPromise?{
          ???static?any(
          ????values:?(T?|?PromiseLike)[]?|?Iterable>
          ??):?MyPromise?{
          ????return?new?MyPromise((resolve,?reject)?=>?{
          ??????//?接收迭代器
          ??????const?iter?=?values[Symbol.iterator]()
          ??????let?cur?=?iter.next()
          ??????const?doneArr:?boolean[]?=?[]
          ??????for?(let?i?=?0;?!cur.done;?i++)?{
          ????????const?value?=?cur.value
          ????????cur?=?iter.next()
          ????????doneArr.push(false)
          ????????if?(isPromise(value))?{
          ???????????//?如果為?thenable,根據(jù)該?thenable?的狀態(tài)進(jìn)行判斷
          ??????????value.then(resolve,?()?=>?{
          ????????????doneArr[i]?=?true
          ??????????????//?只有傳入迭代器的值全是?thenable?并且?thenable?的狀態(tài)全部為?rejected?才會(huì)觸發(fā)
          ????????????if?(cur.done?&&?doneArr.every((item)?=>?item))?{
          ??????????????//?應(yīng)該拋出?AggregateError?的錯(cuò)誤類(lèi)型,但是因?yàn)?AggregateError?因?yàn)槭菍?shí)驗(yàn)版本,所有只有最新版瀏覽器才會(huì)有,我這里就用?Error?代替了
          ??????????????const?e?=?new?Error('All?promises?were?rejected')
          ??????????????e.stack?=?''
          ??????????????reject(e)
          ????????????}
          ??????????})
          ????????}?else?{
          ??????????resolve(value)
          ????????}
          ??????}
          ????})
          ??}
          }

          總結(jié)

          本文使用 typescript,根據(jù)類(lèi)型定義從零開(kāi)始實(shí)現(xiàn)了一個(gè) Promise,其中重點(diǎn)深入了對(duì)于then方法的處理。雖不完美,但也算達(dá)到了想要的效果。作者技術(shù)有限,如果有什么錯(cuò)誤或遺漏的地方還請(qǐng)?jiān)谠u(píng)論區(qū)中指出,順便求個(gè)??。

          文章的代碼已上傳至github:

          https://github.com/Col0ring/learning-es6/tree/main/Promise

          瀏覽 61
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  在线国产播放 | 丁香五月激情啪啪啪 | 免费无码三级片在线观看 | 性爱无码片AV | 色逼视频|