Promise源碼解密-Promise A+標(biāo)準(zhǔn)

      網(wǎng)友投稿 738 2022-05-30

      術(shù)語

      1. Promise

      promise 是一個(gè)擁有 then 方法的 object 或 function ,其行為符合本規(guī)范

      2. thenable

      是一個(gè)定義了 then 方法的 object 或 function

      3. 值(value)

      指任何 JavaScript 的合法值(包括 undefined , thenable 和 promise);

      4. 異常(exception)

      通過throw拋出一個(gè)值

      5. 原因(reason)

      一個(gè)promise被拒絕的原因

      class Promise { constructor(executor) { this.value = undefined; this.reason = undefined; } } function Promise(){} Promise.prototype.then=function(){}

      Promise源碼解密-Promise A+標(biāo)準(zhǔn)

      要求

      1. Promise 的狀態(tài)

      當(dāng)前Promise的狀態(tài)只能是下面三種狀態(tài)中的一種,不能存在多種狀態(tài)。

      示例:

      const STATUS_PENDING = "pending"; const STATUS_FULFILLED = "fulfilled"; const STATUS_REJECTED = "rejected"; class Promise { constructor(executor) { this.status = STATUS_PENDING; } }

      處于等待時(shí),狀態(tài)可以遷移至執(zhí)行態(tài)或拒絕態(tài)

      處于執(zhí)行時(shí):

      不能遷移至其他任何狀態(tài)

      必須擁有一個(gè)不可變的終值

      處于拒絕時(shí):

      不能遷移至其他任何狀態(tài)

      必須擁有一個(gè)不可變的reason

      這里的不可變指的是恒等(即可用 === 判斷相等),引用數(shù)據(jù)類型只要保證地址相等即可。

      new Promise((resolve, reject) => { resolve('成功'); reject('拒絕') }).then((res) => { console.log(res,"res") }, (error) => { console.log(error,'reason') }) new Promise()時(shí)狀態(tài)是pending, 當(dāng)程序執(zhí)行,也就是(resolve, reject) => { resolve('成功'); reject('拒絕') },這個(gè)執(zhí)行 這里resolve把值進(jìn)行了this.value = "成功";,但是并不會(huì)this.reason='拒絕', 這是因?yàn)橹挥谐霈F(xiàn)了執(zhí)行就不會(huì)出現(xiàn)拒絕,最后輸出的結(jié)果是"成功 res", 如果注釋掉resolve('成功');,最后輸出的結(jié)果是 "拒絕 reason"。

      2. Then 方法

      一個(gè) promise 必須提供一個(gè) then 方法以訪問其當(dāng)前值、終值 和 reason。

      promise 的 then 方法接受兩個(gè)函數(shù)參數(shù):

      promise.then(onFulfilled, onRejected) then((res) => { console.log(res,"res") }, (error) => { console.log(error,'reason') })

      如果 onFulfilled 不是函數(shù),必須被忽略

      如果 onRejected 不是函數(shù),必須被忽略

      如果 onFulfilled 是函數(shù):

      當(dāng) promise 執(zhí)行結(jié)束后其必須被調(diào)用,其第一個(gè)參數(shù)為 promise的value

      在 promise 執(zhí)行結(jié)束前其不可被調(diào)用

      其調(diào)用次數(shù)不可超過一次

      new Promise((resolve, reject) => { resolve(123) }).then(result => { console.log(result); }, error => { console.log(error); }); // 這里resolve執(zhí)行結(jié)束才會(huì)執(zhí)行then,這里的result就是終值

      如果 onRejected 是函數(shù):

      當(dāng) promise 被拒絕執(zhí)行后其必須被調(diào)用,其第一個(gè)參數(shù)為 promise 的reason

      在 promise 被拒絕執(zhí)行前其不可被調(diào)用

      其調(diào)用次數(shù)不可超過一次

      onFulfilled 和 onRejected 只有在執(zhí)行環(huán)境堆棧僅包含平臺(tái)代碼時(shí)才可被調(diào)用 >> 注1

      onFulfilled 和 onRejected 必須被作為函數(shù)調(diào)用(即沒有 this 值)>> 注2

      then方法可以被同一個(gè)promise 調(diào)用多次

      當(dāng) promise 成功執(zhí)行時(shí),所有 onFulfilled 需按照其注冊(cè)順序依次回調(diào)

      當(dāng) promise 被拒絕執(zhí)行時(shí),所有的 onRejected 需按照其注冊(cè)順序依次回調(diào)

      new Promise.then().then()

      then 方法必須返回一個(gè) promise 對(duì)象 >> 注3, 這也就是then可以被多次調(diào)用的原因。

      Promise.prototype.then=function(onFulfilled, onRejected){ return new Promise() } promise2 = promise1.then(onFulfilled, onRejected);

      如果 onFulfilled 或者 onRejected 返回一個(gè)值 x ,則運(yùn)行下面的 Promise 解決過程:[[Resolve]](promise2, x)

      promise1.then((value)=>{ return x; }, (reason)=>{ return x }), // 這種情況需要處理x函數(shù)還是值還是其他情況 ,所有用到了 Promise 解決過程 // 這種情況直接 Promise.prototype.then=function(onFulfilled, onRejected){ return let promise2 = new Promise((resolve,reject)=>{ try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }) }

      如果 onFulfilled 或者 onRejected 拋出一個(gè)異常 e ,則 promise2 必須拒絕執(zhí)行,并返回拒因 e

      promise1.then((value)=>{ throw new Error() }, (reason)=>{ throw new Error() }), // 這種情況直接 Promise.prototype.then=function(onFulfilled, onRejected){ return new Promise((resolve,reject)=>{ try { // console.log("執(zhí)行 onFulfilled"); // 這里的x是啥? 是then中回調(diào)的return的返回值 onFulfilled(this.value); 或者 onReject(this.reason) } catch (e) { reject(e); } }) }

      如果 onFulfilled 不是函數(shù)且 promise1 成功執(zhí)行, promise2 必須成功執(zhí)行并返回相同的值

      promise1.then(1,2), Promise.prototype.then=function(onFulfilled, onRejected){ if (this.status === STATUS_FULFILLED) { return new Promise((resolve,reject)=>{ if(typeof onFulfilled !== "function" ){ resolve(onFulfilled) } if(typeof onRejected !== "function" ){ resolve(onRejected) } }) } }

      如果 onRejected 不是函數(shù)且 promise1 拒絕執(zhí)行, promise2 必須拒絕執(zhí)行并返回相同的reason

      promise1.then(1,2), Promise.prototype.then=function(onFulfilled, onRejected){ if (this.status === STATUS_PENDING) { return new Promise((resolve,reject)=>{ reject(onRejected) }) } }

      Promise 解決過程

      Promise 解決過程是需要輸入一個(gè) promise 和一個(gè)值 x 的一個(gè)抽象的操作,稱為 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一個(gè) Promise ,解決程序即嘗試使 promise 接受 x 的狀態(tài);否則其用 x 的值來執(zhí)行 promise 。(x是返回值,請(qǐng)注意上面的例子)

      解決過程步驟:

      x 與 promise 相等

      如果 promise 和 x 指向同一對(duì)象,直接 throw new TypeError

      let p1=new Promise(resolve=>{ resolve() }) let p2=p1.then(data=>{ // 返回了p2 return p2 })

      x 是Promise

      如果 x 是一個(gè) Promise ,則使 promise 接受 x 的狀態(tài) >>注4:

      如果 x 處于等待, promise 需保持等待直至 x 被執(zhí)行或拒絕

      如果 x 處于執(zhí)行,用相同的值執(zhí)行 promise

      如果 x 處于拒絕,用相同的reason拒絕 promise

      x 為對(duì)象或函數(shù)

      如果 x 為對(duì)象或者函數(shù):

      把 x.then 賦值給 then>> 注5

      如果取 x.then 的值時(shí)拋出錯(cuò)誤 e ,則以 e 為reason拒絕 promise

      如果then是函數(shù),將x作為函數(shù)的作用域this調(diào)用。傳遞兩個(gè)回調(diào)函數(shù)作為參數(shù),第一個(gè)參數(shù)叫做resolvePromise

      ,第二個(gè)參數(shù)叫做rejectPromise:

      如果 resolvePromise 以值 y 為參數(shù)被調(diào)用,則運(yùn)行 [[Resolve]](promise, y)

      如果 rejectPromise 以reason r 為參數(shù)被調(diào)用,則以reason r 拒絕 promise

      如果 resolvePromise 和 rejectPromise 均被調(diào)用,或者被同一參數(shù)調(diào)用了多次,則優(yōu)先采用首次調(diào)用并忽略剩下的調(diào)用

      如果調(diào)用then方法拋出了異常e:

      如果 resolvePromise 或 rejectPromise 已經(jīng)被調(diào)用,則忽略之

      否則以 e 為reason拒絕 promise

      如果 then 不是函數(shù),以 x 為參數(shù)執(zhí)行 promise

      如果 x 不為對(duì)象或者函數(shù),以 x 為參數(shù)執(zhí)行 promise

      function resolvePromise(promise2, x, resolve, reject) { // 用來保存是否已經(jīng)reject或者resolve過 let called if (promise2 === x) { throw new TypeError('Chaining cycle detected for promise') } // 如果是函數(shù)或者object的話先默認(rèn)是promise if (x != null && (typeof x === 'object' || typeof x === 'function')) { try { let then = x.then // 如果then是函數(shù)的話 if (typeof then === 'function') { // 為啥不直接x.then() // 因?yàn)閠hen已經(jīng)判斷過是不是function,但是x.then沒有判斷過 // 就讓then執(zhí)行 第一個(gè)參數(shù)是this 后面是成功的回調(diào) 和 失敗的回調(diào) // 這里的y是啥,如果x是promsie的話,那么y就是x中的resolve/reject的值 then.call(x, y => { // 成功和失敗只能調(diào)用一個(gè) if (called) return; called = true; // resolve的結(jié)果依舊是promise 那就繼續(xù)解析 resolvePromise(promise2, y, resolve, reject); }, err => { // 成功和失敗只能調(diào)用一個(gè) if (called) return; called = true; reject(err); }) } else { resolve(x); // 如果不是函數(shù),那就直接返回結(jié)果 } } catch (error) { // 成功和失敗只能調(diào)用一個(gè) if (called) return; called = true; // 沒有then 不是函數(shù)也不是普通值 reject(error) } } else { // x 是一個(gè)普通值 resolve(x) } }

      如果一個(gè) promise 被一個(gè)循環(huán)的 thenable 鏈中的對(duì)象解決,而 [[Resolve]](promise, thenable) 的遞歸性質(zhì)又使得其被再次調(diào)用,根據(jù)上述的算法將會(huì)陷入無限遞歸之中。算法雖不強(qiáng)制要求,但也鼓勵(lì)施者檢測(cè)這樣的遞歸是否存在,若檢測(cè)到存在則以一個(gè)可識(shí)別的 TypeError 為reason來拒絕 promise >>注6。

      注釋

      注1 這里的平臺(tái)代碼指的是引擎、環(huán)境以及 promise 的實(shí)施代碼。實(shí)踐中要確保 onFulfilled 和 onRejected 方法異步執(zhí)行,且應(yīng)該在 then 方法被調(diào)用的那一輪事件循環(huán)之后的新執(zhí)行棧中執(zhí)行。這個(gè)事件隊(duì)列可以采用“宏任務(wù)(macro-task)”機(jī)制或者“微任務(wù)(micro-task)”機(jī)制來實(shí)現(xiàn)。由于 promise 的實(shí)施代碼本身就是平臺(tái)代碼(**譯者注:**即都是 JavaScript),故代碼自身在處理在處理程序時(shí)可能已經(jīng)包含一個(gè)任務(wù)調(diào)度隊(duì)列。

      注2 也就是說在**嚴(yán)格模式(strict)**中,函數(shù) this 的值為 undefined ;在非嚴(yán)格模式中其為全局對(duì)象。

      注3 代碼實(shí)現(xiàn)在滿足所有要求的情況下可以允許 promise2 === promise1 。每個(gè)實(shí)現(xiàn)都要文檔說明其是否允許以及在何種條件下允許 promise2 === promise1 。

      注4 總體來說,如果 x 符合當(dāng)前實(shí)現(xiàn),我們才認(rèn)為它是真正的 promise 。這一規(guī)則允許那些特例實(shí)現(xiàn)接受符合已知要求的 Promises 狀態(tài)。

      注5 這里我們存儲(chǔ)了x.then的引用 ,然后在if中進(jìn)行判斷,并且可以避免多次訪問 x.then 屬性。同時(shí)這確保了該屬性的一致性,因?yàn)槠渲悼赡茉跈z索調(diào)用時(shí)被改變。

      注6 實(shí)現(xiàn)不應(yīng)該對(duì) thenable 鏈的深度設(shè)限,并假定超出本限制的遞歸就是無限循環(huán)。只有真正的循環(huán)遞歸才應(yīng)能導(dǎo)致 TypeError 異常;如果一條無限長的鏈上 thenable 均不相同,那么遞歸下去永遠(yuǎn)是正確的行為。

      Promise

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:女朋友桌面文件雜亂無章?氣得我用Python給她做了一個(gè)文件整理工具
      下一篇:Python命名空間和作用域淺析
      相關(guān)文章
      亚洲成av人在线观看网站| 亚洲欧洲一区二区| 亚洲精品在线播放| 日韩亚洲人成在线综合日本| 亚洲AV中文无码乱人伦在线视色| 亚洲人精品亚洲人成在线| 亚洲制服丝袜精品久久| 911精品国产亚洲日本美国韩国| 亚洲国产精品嫩草影院在线观看| 亚洲中文字幕无码不卡电影| 亚洲熟妇少妇任你躁在线观看无码| 亚洲国产精品无码观看久久| 亚洲av无码成人影院一区| 亚洲精品9999久久久久无码| 国产精品无码亚洲精品2021| 国产精品无码亚洲精品2021| 一本色道久久88亚洲综合| 国产亚洲日韩在线a不卡| 亚洲成AⅤ人影院在线观看 | 亚洲人成国产精品无码| 亚洲精品国产精品乱码不卡 | 亚洲欧洲在线观看| 亚洲视频小说图片| 亚洲国产精品乱码在线观看97| 亚洲成a人片在线观看中文app| 亚洲日本香蕉视频| 亚洲一级毛片中文字幕| 亚洲www77777| 九九精品国产亚洲AV日韩| 亚洲a∨无码一区二区| 亚洲精品无码你懂的网站| 久久久久亚洲AV无码专区网站| 亚洲色偷偷偷鲁综合| 久久亚洲免费视频| 久久精品国产亚洲AV无码娇色| 亚洲女人影院想要爱| 亚洲中文字幕精品久久| 亚洲AⅤ无码一区二区三区在线| 久久亚洲av无码精品浪潮| 亚洲国产另类久久久精品小说| 亚洲高清在线观看|