日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Promise深度学习---我のPromise/A+实现

發(fā)布時(shí)間:2025/7/14 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Promise深度学习---我のPromise/A+实现 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文地址fancierpj0.github.io/iPromise/

目錄 (づ ̄ 3 ̄)づ=> 掘金這目錄頁。。放這么角落。。嗯。。干撒呢

[TOC]

本文會對Promise規(guī)范進(jìn)行一個(gè)比較完整的實(shí)現(xiàn),目的是為了加深對Promise各個(gè)特性的理解從而更好的應(yīng)用。

[warning] 注意:本文依據(jù)Promises/A+規(guī)范進(jìn)行Promise的實(shí)現(xiàn)

1.Promise/A+ 術(shù)語

1.1. promise

promise是一個(gè)對象或則函數(shù),它的表現(xiàn)是依據(jù)Promises/A+這篇規(guī)范說明來定義的。

1.1. promise is an object or function with a then method whose behavior conforms to this specification.

1.2. theable

thenable是一個(gè)定義了then方法的對象或則函數(shù)。

thenable is an object or function that defines a then method.

1.3. value

value可以是任何合法的JS值,甚至包括undefined、一個(gè)thenable、一個(gè)promise。

value is any legal JavaScript value (including undefined, a thenable, or a promise).

1.4. exception

exception是一個(gè)用throw語句拋出的值。

exception is a value that is thrown using the throw statement.

1.5. reason

reason是一個(gè)為什么promise會被拒絕的理由。

reason is a value that indicates why a promise was rejected.

Promise規(guī)范要求

判斷一個(gè)東東是不是Promise,有三項(xiàng)主要的特征可作為參考

  • Promise有三種狀態(tài) pending 、fulfilled、rejected
  • Promise含有then方法
  • Promise含有Promise Resolution Procedure (promise的狀態(tài)轉(zhuǎn)換處理方法)。

2.1. Promise狀態(tài)

一個(gè)promise必須處于 pending 、fulfilled、rejected 三種狀態(tài)中的其中一種

下面是一個(gè)promise最基本的使用demo,我們先有個(gè)印象。

  • 其中promise實(shí)例化的時(shí)候傳入了一個(gè)函數(shù)作為參數(shù),這個(gè)函數(shù)我們稱之為 executor ,它能告訴我們何時(shí)將promise狀態(tài)從pending轉(zhuǎn)化為其余兩態(tài)中的一態(tài)。
  • 而 then 方法是實(shí)例化對象下的一個(gè)方法,它能傳入兩個(gè)參數(shù),一般是兩個(gè)回調(diào)函數(shù),對應(yīng)fulfilled和rejected兩個(gè)狀態(tài),當(dāng)promise從pengding狀態(tài)轉(zhuǎn)化成其中一個(gè)狀態(tài)時(shí)就會觸發(fā)對應(yīng)的回調(diào)函數(shù)。
let p = new Promise((resolve,reject)=>{let x = Math.random();console.log(x);if (x > .5) {resolve('我是你許下的諾言的那個(gè)東東');} else {reject('我是你未能實(shí)現(xiàn)諾言的理由');} });p.then((value)=>{ //綁定成功時(shí)的回調(diào)函數(shù)console.log('fulfilled:',value); //fulfilled:我是你許下的諾言的那個(gè)東東 },(reason)=>{ //綁定失敗時(shí)的回調(diào)函數(shù)console.log('rejected:',reason); //rejected:我是你未能實(shí)現(xiàn)諾言的理由 }); 復(fù)制代碼

2.1.1. pending狀態(tài)

當(dāng)Promise處于pending狀態(tài)時(shí),它可能轉(zhuǎn)換為fulfilled或則rejected狀態(tài)。

When pending, a promise:may transition to either the fulfilled or rejected state.

2.1.2. fulfilled狀態(tài)

當(dāng)Promise處于fulfilled狀態(tài)時(shí),它不再能轉(zhuǎn)換為其它狀態(tài) 且 它必須有一個(gè)值,這個(gè)值不能被更改。

When fulfilled, a promise:

  • must not transition to any other state.
  • must have a value, which must not change.

2.1.3 rejected狀態(tài)

當(dāng)promise處于rejected時(shí),它不再能轉(zhuǎn)換為其它狀態(tài) 且 它必須有一個(gè)理由,這個(gè)理由不能被更改。

When rejected, a promise:

  • must not transition to any other state.
  • must have a reason, which must not change.

[danger]注意: 當(dāng)promise處于fulfilled或則rejected時(shí),它都有一個(gè)值,這個(gè)值不能被更改,但是可以像使用常量一樣在這個(gè)值下面掛載其它值。

Here, “must not change” means immutable identity (i.e. ===), but does not imply deep immutability.

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

請先回顧一下我們在說Promise狀態(tài)時(shí)候最初的那個(gè)demo 我們通過實(shí)例化Promise時(shí)傳入了一個(gè)參數(shù),這個(gè)參數(shù)是一個(gè)執(zhí)行函數(shù)(executor),它能決定什么時(shí)候?qū)romise轉(zhuǎn)換成fulfilled什么時(shí)候轉(zhuǎn)換成rejected。

const PENDING = 'pending'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected';function Promise(executor){let self = this; //緩存下self.value = undefined; //用來存放value和reason,因?yàn)閜romise只會處于一種狀態(tài)故可只用一個(gè)變量來表示。self.status = PENDING; //將初始狀態(tài)設(shè)置為pendingself.onFulfilledCallbacks = []; //用來存放所有成功的回調(diào)函數(shù)self.onRejectedCallbacks = []; //用來存放所有失敗的回調(diào)函數(shù)try{executor(resolve,reject); //調(diào)用執(zhí)行函數(shù),將resolve和reject方法作為參數(shù)傳入}catch (e){reject(e); //若執(zhí)行函數(shù)中存在異常直接用拋出的值來拒絕promise}//-----------------------------------------------------------------------------------------------------------function resolve(value){ //此方法會隨著executor傳入而傳入setTimeout(function(){if(self.status === PENDING){ //確保狀態(tài)只會改變一次self.status = FULFILLED; //改變狀態(tài)self.value = value; //賦予一個(gè)值self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.2. //2.2.6.}})}function reject(reason){setTimeout(function(){if(self.status === PENDING){self.status = REJECTED;self.value = reason;self.onRejectedCallbacks.forEach(cb => cb(self.value));}})} }復(fù)制代碼

以上實(shí)現(xiàn)了2.1. ,promise的三種狀態(tài)以及狀態(tài)之間的改變。

executor,形參、實(shí)參、作用域鏈

我們可以發(fā)現(xiàn)最終轉(zhuǎn)換狀態(tài)時(shí)通過Promise內(nèi)部的兩個(gè)方法resolve和reject,這個(gè)兩個(gè)方法是在什么時(shí)候傳入的呢? 一個(gè)函數(shù)的參數(shù)查找,是從調(diào)用這個(gè)函數(shù)時(shí)所處的作用域開始查找的。 new Promise傳入的executor,是參數(shù)也是對executor函數(shù)的定義,此時(shí)executor的resolve和reject為形參。 我們new Promise的時(shí)候,會執(zhí)行構(gòu)造函數(shù)Promise內(nèi)的代碼,也就是在這時(shí)executor被執(zhí)行,而executor此時(shí)所處的作用域是在Promise構(gòu)造函數(shù)內(nèi)部,resolve和reject方法作為實(shí)參被傳入。

2.2. then方法

一個(gè)promise必須提供一個(gè)then方法來使用它將要或則說已經(jīng)被賦予的 value 或則 reason,一個(gè)promise的then方法接收兩個(gè)參數(shù)

promise.then(onFulfilled,onRejected) 復(fù)制代碼

2.2.1. then參數(shù)

then中的參數(shù)皆為可選參數(shù),如果onFulfilled或則說onRejected不是一個(gè)函數(shù),那么將會被忽略。

Both onFulfilled and onRejected are optional arguments:

  • If onFulfilled is not a function, it must be ignored.
  • If onRejected is not a function, it must be ignored.

2.2.2. 如果onFulfilled是一個(gè)函數(shù)

  • 如果onFulfilled是一個(gè)函數(shù),它必須在promise狀態(tài)轉(zhuǎn)換為fulfilled時(shí)候就被調(diào)用,并且promise被賦予的value會成為這個(gè)函數(shù)(onFulfilled)的第一個(gè)參數(shù)。
  • onFulfilled不能在promise狀態(tài)轉(zhuǎn)化為fulfilled前就調(diào)用
  • onFulfilled函數(shù)不能重復(fù)調(diào)用

原文規(guī)范詳見Promises/A+

2.2.3. 如果onRejected是一個(gè)函數(shù)

  • 如果onRejected是一個(gè)函數(shù),它必須在promise狀態(tài)轉(zhuǎn)換為rejected時(shí)候就被調(diào)用,并且promise被賦予的reason會成為這個(gè)函數(shù)(onRejected)的第一個(gè)參數(shù)。
  • onRejected不能在promise狀態(tài)轉(zhuǎn)化為rejected前就調(diào)用
  • onRejected函數(shù)不能重復(fù)調(diào)用

2.2.4. onFulfilled 或則 onRejected 必須在執(zhí)行棧 只存在 platform code 時(shí)才能被調(diào)用。

2.2.5. onFulfilled 和 onRejected 必須被當(dāng)做函數(shù)調(diào)用。

2.2.6. 同一個(gè)promise實(shí)例可以調(diào)用多次then

  • 當(dāng)一個(gè)promise轉(zhuǎn)化為fulfilled狀態(tài),所有onFulfilled callback會按照回調(diào)函數(shù)通過then添加時(shí)的順序而執(zhí)行。
  • 當(dāng)一個(gè)promise轉(zhuǎn)化為rejected狀態(tài),所有onRejected callback會按照回調(diào)函數(shù)通過then添加時(shí)的順序而執(zhí)行。

:then在同一個(gè)promise實(shí)例下多次調(diào)用,意味著可以在同一個(gè)promise的同一種狀態(tài)下綁定多個(gè)不同的回調(diào)函數(shù),而這些回調(diào)函數(shù)執(zhí)行的順序和它們被綁定時(shí)的順序相同。

2.2.7. then必會返回一個(gè)新的promise

promise2 = promise1.then(onFulfilled,onRejected); 復(fù)制代碼
  • 如果onFulfilled或onRejected回調(diào)函數(shù)中返回了一個(gè)值,假定為x,那么調(diào)用一個(gè) promise解析方法 [[Resolve]](promise2,x)。
  • 如果onFulfilled或者onRejected拋出了一個(gè) exception(異常) e , promise2 必須以這個(gè)e作為reason來拒絕promise,使其狀態(tài)改變?yōu)閞ejected。
  • 如果onFulfilled不是一個(gè)函數(shù)且 promise1 的狀態(tài)為fulfilled,promise2必須以 promise1 的值來fulfilled。
  • 如果onRejected不是一個(gè)函數(shù)且 promise1 的狀態(tài)為rejected,promise2必須以 promise1 的理由來rejected。

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

2.2.提的是一個(gè)then的實(shí)現(xiàn)規(guī)則,而then主要作用為promise綁定回調(diào)函數(shù),當(dāng)promise轉(zhuǎn)換狀態(tài)時(shí)會自動調(diào)用對應(yīng)的回調(diào)函數(shù)。(對應(yīng)規(guī)范2.2.2-2.2.3) 其實(shí)就是發(fā)布訂閱模式啦

function Promise(){...function resolve(value){ setTimeout(function(){ //2.2.4.if(self.status === PENDING){ //2.2.2.3-2.2.2.4self.status = FULFILLED; self.value = value; self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.6.}})}function reject(reason){setTimeout(function(){if(self.status === PENDING){ //2.2.3.3-2.2.3.4self.status = REJECTED;self.value = reason;self.onRejectedCallbacks.forEach(cb => cb(self.value));}})} } //--------------------------------------------------------------------------------------------------- Promise.prototype.then = function (onFulfilled, onRejected) { //2.2.1.//2.2.7.3-2.2.7.4 //2.2.5.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};let self = this,promise2; //2.2.7.0 //聲明要返回的promise2if(self.status === PENDING){//2.2.7.return promise2 = new Promise(function(resolve,reject){//存儲then方法綁定的回調(diào)函數(shù) //2.2.6.self.onFulfilledCallbacks.push((value)=>{try{let x = onFulfilled(value);resolvePromise(promise2,x,resolve,reject); //2.2.7.1}catch (e){reject(e); //2.2.7.2}});self.onRejectedCallbacks.push((reason)=>{try{let x= onRejected(reason);resolvePromise(promise2,x,resolve,reject);}catch (e){reject(e);}});});} }; 復(fù)制代碼

關(guān)于platform code

Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

上面一大段話的意思大致上就是要求 onFulfilled 和 onRejected 回調(diào)函數(shù)確保異步執(zhí)行。我們可以選擇用宏任務(wù)(setTimeout/setImmediate)或則微任務(wù)(process.nextTix/MutationObserver)來完成這項(xiàng)規(guī)范。

這里我們通過在Promise中的resolve和reject方法中套了一個(gè)setTimeout()來實(shí)現(xiàn)。

function resolve(value){ setTimeout(function(){ //2.2.4.if(self.status === PENDING){ //2.2.2.3-2.2.2.4self.status = FULFILLED; self.value = value; self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.6.}})} 復(fù)制代碼

這樣setTimeout中的代碼就會在下一個(gè)新的執(zhí)行棧中執(zhí)行。即使executor中的代碼是同步代碼也一樣

let p = new Promise((resolve,reject)=>{setTimeout(()=>{resolve('resolve');}) }); p.then((value)=>{console.log('fulfilled:',value); },(reason)=>{console.log('rejected:',reason); }); console.log('----------------');//輸出 >>>---------------- >>>fulfilled: resolve //---------------------------------------------------------------------------------- let p = new Promise((resolve,reject)=>{resolve('resolve'); }); p.then((value)=>{console.log('fulfilled:',value); },(reason)=>{console.log('rejected:',reason); }); console.log('----------------');//輸出 >>>---------------- >>>fulfilled: resolve 復(fù)制代碼

情景:值的穿透

下面的例子中本應(yīng)是第一個(gè)then中的參數(shù)會穿透到第二then中作為參數(shù)。 下面兩句再集合resolvePromise方法即是穿透原因

Promise.prototype.then = function (onFulfilled, onRejected) { //2.2.1.//2.2.7.3-2.2.7.4 //2.2.5.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; //結(jié)合resolvePromise方法即是穿透原因onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}; //繼續(xù)把異常往后拋...//------------------------------------------------- let p = new Promise((resolve,reject)=>{resolve('resolve'); }); p.then().then((value)=>{console.log(value); //會輸出resolve }); 復(fù)制代碼

2.3. Promise狀態(tài)解析方法(promise resolution procedure)

let x= onRejected(reason); resolvePromise(promise2,x,resolve,reject); //resolve/reject為promise2的resolve/reject 復(fù)制代碼

Promise狀態(tài)解析方法的作用是將then時(shí)返回的promise2的狀態(tài)改變并賦予其vlaue/reason。

  • 如果 x 是一個(gè)thenable,那么該方法將試圖將以 x 的狀態(tài)來改變 promise2 的狀態(tài)
  • 否則就將 promise2 改成 fulfilled 狀態(tài),并且value即為 x 的值

2.3.1. 如果 promise2 和 x 是引用關(guān)系,則拋出一個(gè) TypeError 做為理由來 reject promise2。

2.3.2. 如果 x 是一個(gè)promise ,讓promise2采用它的狀態(tài)。

  • 如果 x 處于pending,promise2 必須保持pending直到 x 轉(zhuǎn)換為 fulfilled或則rejected。
  • 如果 x 是 fulfilled狀態(tài),讓promise2也為fulfilled,并且讓promise2的value為x的value。
  • 如果 x 是 rejected狀態(tài),讓promise2也為rejected,并且讓promise2的value為x的reason。

2.3.3. 如果 x 是一個(gè)對象或則函數(shù)

  • Let then be x.then
  • 如果檢索 x.then 時(shí)候拋出了一個(gè)異常e,那么以這個(gè) e來 rejecte promise2。
  • 如果 then 是一個(gè)函數(shù),用x作為this,resolvePromise作為第一個(gè)參數(shù),rejectPromise作為第二個(gè)參數(shù)來 call它。
    • 如果resolvePromise被調(diào)用,循環(huán)調(diào)用 promise狀態(tài)解析方法(原本的x替換為調(diào)用resolvePromise傳入的參數(shù),假定為y)。
    • 如果rejectPromise被調(diào)用,則reject Promise2,reason為調(diào)用rejectPromise傳入的參數(shù)
    • 如果resolvePromise 和 rejectPromise 同時(shí)被調(diào)用或則多次調(diào)用,那么第一個(gè)調(diào)用的擁有優(yōu)先權(quán),其它的會被忽略。
    • 如果調(diào)用 then 的時(shí)候拋出了一個(gè)異常 e
      • 如果 resolvePromise 或 rejectPromise 已經(jīng)被調(diào)用,則忽略它。
      • 否則,則用這個(gè)e來 reject promise2。
  • 如果then不是一個(gè)函數(shù),則用x來fulfilledpromise2

2.3.4. 如果 x 不是一個(gè)函數(shù)也不是一個(gè)對象,則用x來fulfilledpromise2

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

resolvePromise方法針對的是then綁定的回調(diào)函數(shù)中的return值進(jìn)行解析,一般情況是:

  • 當(dāng)return的是普通類型的值,那么會以這個(gè)值來fulfilled promise2
  • 如果是一個(gè)promise,那么會以這個(gè)x promise的結(jié)果來fulfilled/rejected promise2
function resolve(value) {if(value instanceof Promise){ //和resolvePromise有點(diǎn)聯(lián)系的是 當(dāng)then return的promise中又resolve了一個(gè)promise會先走這,會將resolve里的promise的值賦給調(diào)用resolve的promise(說法欠妥,意會即可)return value.then(resolve,reject); //這意味著如果promise1 resolve中是一個(gè)promise2,那么promise1狀態(tài)的改變時(shí)間會被推遲,直到promise2狀態(tài)改變調(diào)用promise2的回調(diào)時(shí),promise1狀態(tài)才會改變才會觸發(fā)promise1的回調(diào)} ... //--------------------------------------------------------------------------------------------------------- function resolvePromise(promise2,x,resolve,reject){if(x === promise2){ //2.3.1.return reject(new TypeError('禁止循環(huán)引用!'));}let called =false;//2.3.2.if(x instanceof Promise){if(x.status === PENDING){ //2.3.2.1x.then((y)=>{resolvePromise(promise2,y,resolve,reject); //因?yàn)榇藭r(shí)的y,有可能也是一個(gè)promise //掛上一個(gè)鉤子只要x狀態(tài)轉(zhuǎn)化為成功態(tài)就遞歸調(diào)用resolvePromise},reject);}else{ //此分支存在的意義在于若executor調(diào)用resolve/reject不是異步的且不在resolve/reject中設(shè)置setTimeout,意味著當(dāng)new的時(shí)候就會返回一個(gè)帶狀態(tài)的promise就會走這里。x.then(resolve,reject); //2.3.2.2-2.3.2.3 //只要x狀態(tài)改變,就以x的狀態(tài)和值來改變promise2的狀態(tài)和值 //這個(gè)值可能是一個(gè)promise,前提是在上面那種假設(shè)實(shí)現(xiàn)中 //如果不符合上面那種實(shí)現(xiàn)且不想像規(guī)范一樣允許值可以為一個(gè)promise或則對象 可除去此分支}}else if(x!=null&&((typeof x === 'function')||(typeof x === 'object'))){ //2.3.3.try{let then = x.then; //2.3.3.1if(typeof then === 'function'){//2.3.3.3.then.call(x,(y)=>{if(called) return; //2.3.3.3.3.called = true;resolvePromise(promise2,y,resolve,reject); //在resolve中又包含promise的情況下,由于resolve中的 value.then存在,當(dāng)前回調(diào)調(diào)用時(shí),resolve中的promise狀態(tài)一定已經(jīng)改變,在狀態(tài)已經(jīng)改變的時(shí)候利用then綁定回調(diào),會走then中的status==fulfilled或則rejected分支},(reason)=>{if(called) return;called = true;reject(reason);});}else{resolve(x); //2.3.3.4. //1.3}}catch (e){if(called) return; //2.3.3.3.4.1.called = true;reject(e); //2.3.3.2. //2.3.3.3.4.2.}}else{ //2.3.4.resolve(x);} } 復(fù)制代碼

情景:當(dāng)return的是promise且該promise的resolve/reject ()中 也是一個(gè)promise

let p = new Promise((resolve,reject)=>{resolve('resolve1'); }); p.then((value)=>{return new Promise((resolve,reject)=>{resolve(new Promise((resolve,reject)=>{setTimeout(()=>{resolve('別慫')});}));}); }).then((value)=>{console.log(value); //別慫 }); console.log('----------------'); 復(fù)制代碼

可見最終的value值為最里層的value值,這樣的實(shí)現(xiàn)關(guān)鍵在于遞歸調(diào)用resolvePromise。

... function resolve(value) {if(value instanceof Promise){ return value.then(resolve,reject); ...if(x instanceof Promise){if(x.status === PENDING){ //2.3.2.1x.then((y)=>{resolvePromise(promise2,y,resolve,reject); },reject);}else{x.then(resolve,reject); }}復(fù)制代碼

以上這段代碼,當(dāng)promise1執(zhí)行回調(diào)的時(shí)候,會將x傳入resolvePromise執(zhí)行,此時(shí)由于resolve()方法中的setTimeout,該x是pending狀態(tài)進(jìn)pending分支,該分支會為X掛上一個(gè)鉤子,當(dāng)它狀態(tài)轉(zhuǎn)換后會再次調(diào)用resolvePromise。

  • 如果x的resolve中傳入的也是一個(gè)promise (y),由于resolve中添加的value.then,它會推遲x的狀態(tài)轉(zhuǎn)換,這意味著X狀態(tài)轉(zhuǎn)換時(shí),y的狀態(tài)一定已經(jīng)轉(zhuǎn)換,于是會走下面那個(gè)分支,調(diào)用y.then,而因?yàn)閥的狀態(tài)已經(jīng)轉(zhuǎn)換,在then方法中此時(shí)就不再能通過狀態(tài)改變時(shí)觸發(fā)回調(diào)函數(shù),故要支持此功能需要在then中添加self.status===FULFILLED/REJECTED分支。
}else if(self.status === FULFILLED){return promise2 = new Promise(function(resolve,reject){setTimeout(function(){try{let x =onFulfilled(self.value);resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}})});}else{return promise2 = new Promise(function(resolve,reject){setTimeout(function(){try{let x =onRejected(self.value);resolvePromise(promise2,x,resolve,reject);}catch(e){reject(e);}})});} 復(fù)制代碼

這里用了setTimeout是為了確保回調(diào)函數(shù)會異步執(zhí)行。(針對2.2.4.)

  • 如果x的resolve傳入的只是一個(gè)普通的值。。。呵呵噠,那就直接resolve(x)咯

[warning] 值得注意的是: 如果沒有在 resolve() 方法中對value進(jìn)行判斷,那么此時(shí)嵌套promise中再嵌套一層promise輸出結(jié)果會是一個(gè)promise。因?yàn)榈诙€(gè)promise不會等第三個(gè)promise狀態(tài)轉(zhuǎn)換后才轉(zhuǎn)換狀態(tài),這意味著第二個(gè)promise的值就為第三個(gè)promise對象。

情景:當(dāng)new的promise中的resolve也是一個(gè)promise,而這個(gè)promise的resolve中又是一個(gè)promise...

此時(shí)情況同上個(gè)情景,得益于then()中對value的判斷,它會推遲父promise狀態(tài)的轉(zhuǎn)變。 如果沒有這個(gè)判斷和推遲,那么也可能最終得到的value是個(gè)promise對象。(這是規(guī)范允許的,但NodeJS和blubird對promise規(guī)范的實(shí)現(xiàn)都對父promise的狀態(tài)轉(zhuǎn)換進(jìn)行了推遲)

情景:在一個(gè)已經(jīng)轉(zhuǎn)換了狀態(tài)的promise中再次調(diào)用這個(gè)promise的then方法

此時(shí)也會走then中的self.status === FULFILLED/REJECTED 的分支,再次證明需要在then中添加這兩個(gè)分支并用上settimeout

p1.then((value)=>{ //執(zhí)行此回調(diào)時(shí)p1狀態(tài)已經(jīng)改變p1.then(...); }); 復(fù)制代碼

x instanceof Promise 和 typeof x=function... 遞歸的區(qū)別

instance分支下的遞歸 因?yàn)榇嬖趯romise狀態(tài)的判斷,當(dāng)resolve()沒有對value進(jìn)行判斷時(shí),instance分支下的結(jié)果value最終可能為promise對象,而x.then分支下因?yàn)闆]有對promise狀態(tài)進(jìn)行判斷,故不會出現(xiàn)value為promise對象的情況。

其余Promise方法的實(shí)現(xiàn)

Promise.prototype.catch

此方法實(shí)現(xiàn)灰常簡單,只需在最后一個(gè)then綁定完回調(diào)后再綁定一個(gè)錯(cuò)誤的回調(diào)即可

promise.prototype.catch = function(onRejected){this.then(null,onRejected); } 復(fù)制代碼

Promise.all

此方法傳入一組promise實(shí)例再返回一個(gè)最終的promise實(shí)例,當(dāng)所有promise都轉(zhuǎn)為fulfilled時(shí)返回的最終的promise實(shí)例將會轉(zhuǎn)換為fulfilled,此時(shí)這個(gè)promise的值為傳入的promise的值的集合。而如果傳入的那組promise中有一個(gè)rejected,返回的promise就會rejected。

Promise.all = function(promises){return new Promise((resolve,reject)=>{let result = [],count = 0;function done(i,data){result[i] = data;if(++count===promises.length){resolve(result);}}for(let i=0;i<promises.length;++i){promises[i].then((value)=>{done(i,value);},(reason)=>{reject(reason);});}}); } 復(fù)制代碼

Promise.race

也是傳入一組promise返回一個(gè)promise,哪個(gè)promise先轉(zhuǎn)換狀態(tài),就返回這個(gè)promise的結(jié)果

Promise.race = function(promises){return new Promise((resolve,reject)=>{for(let i=0;i<promises.length;++){promises[i].then(resolve,reject);}}); } 復(fù)制代碼

Promise.promisify

將一個(gè)異步函數(shù)promise化,使其可以then,可以鏈?zhǔn)綍鴮?/p> Promise.promisify = function(fn){return function(...args){return new Promise((resolve,reject)=>{fn.apply(null,[...args,function(err,data){err?reject(err):resolve(data);}]);});} } 復(fù)制代碼

Promise.promisifyAll

將一個(gè)對象下的所有方法都promisify化

Promise.promisifyAll = function(obj){for(var attr in obj){if(obj.hasOwnProperty(key)&&typeof obj[attr]==='function'){obj[attr+'Async'] = Promise.promisify(obj[attr]);}} } 復(fù)制代碼

測試

要對實(shí)現(xiàn)的Promise進(jìn)行測試,除了實(shí)現(xiàn)t規(guī)范要求then方法和catch方法外還需要先在你的promise下添加一個(gè)方法

Promise.deferred = Promise.defer = function(){let defer = {};defer.promise = new Promise(function(resolve,reject){defer.resolve = resolve;defer.reject = reject;});return defer; } 復(fù)制代碼

然后按下述進(jìn)行測試

npm i -g promises-aplus-tests promises-aplus-tests yourFileName.js 復(fù)制代碼

實(shí)現(xiàn)代碼【終板】

const PENDING = 'pending'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected';function Promise(executor) {let self = this; //緩存下self.value = undefined; //用來存放value和reason,因?yàn)閜romise只會處于一種狀態(tài)故可只用一個(gè)變量來表示。self.status = PENDING; //將初始狀態(tài)設(shè)置為pendingself.onFulfilledCallbacks = []; //用來存放所有成功的回調(diào)函數(shù)self.onRejectedCallbacks = []; //用來存放所有失敗的回調(diào)函數(shù)try {executor(resolve, reject); //調(diào)用執(zhí)行函數(shù),將resolve和reject方法作為參數(shù)傳入} catch (e) {reject(e); //若執(zhí)行函數(shù)中存在異常直接用拋出的值來拒絕promise}function resolve(value) {if (value instanceof Promise) { //和resolvePromise有點(diǎn)聯(lián)系的是 當(dāng)then return的promise中又resolve了一個(gè)promise會先走這,會將resolve里的promise的值賦給調(diào)用resolve的promise(說法欠妥,意會即可)return value.then(resolve, reject); //這意味著如果promise1 resolve中是一個(gè)promise2,那么promise1狀態(tài)的改變時(shí)間會被推遲,直到promise2狀態(tài)改變調(diào)用promise2的回調(diào)時(shí),promise1狀態(tài)才會改變才會觸發(fā)promise1的回調(diào)}setTimeout(function () {if (self.status === PENDING) {self.status = FULFILLED;self.value = value;self.onFulfilledCallbacks.forEach(cb => cb(self.value)); //2.2.2. //2.2.6.}})}function reject(reason) {setTimeout(function () {if (self.status === PENDING) {self.status = REJECTED;self.value = reason;self.onRejectedCallbacks.forEach(cb => cb(self.value)); //2.2.3. //2.2.6.}})} }Promise.prototype.then = function (onFulfilled, onRejected) { //2.2.1.//2.2.7.3-2.2.7.4 //2.2.5.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};let self = this,promise2; //2.2.7.0 //聲明要返回的promise2if (self.status === PENDING) {//2.2.7.return promise2 = new Promise(function (resolve, reject) {//存儲then方法綁定的回調(diào)函數(shù) //2.2.6.self.onFulfilledCallbacks.push((value) => {try {let x = onFulfilled(value);resolvePromise(promise2, x, resolve, reject); //2.2.7.1 //resolve/reject屬于promise2 //若此方法執(zhí)行說明promise1狀態(tài)已經(jīng)更改} catch (e) {reject(e); //2.2.7.2}});self.onRejectedCallbacks.push((reason) => {try {let x = onRejected(reason);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}});});} else if (self.status === FULFILLED) {return promise2 = new Promise(function (resolve, reject) {setTimeout(function () {try {let x = onFulfilled(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})});} else {return promise2 = new Promise(function (resolve, reject) {setTimeout(function () {try {let x = onRejected(self.value);resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e);}})});}};function resolvePromise(promise2, x, resolve, reject) {if (x === promise2) { //2.3.1.return reject(new TypeError('禁止循環(huán)引用!'));}let called = false;//2.3.2.if (x instanceof Promise) {if (x.status === PENDING) { //2.3.2.1x.then((y) => {resolvePromise(promise2, y, resolve, reject); //因?yàn)榇藭r(shí)的y,有可能也是一個(gè)promise //掛上一個(gè)鉤子只要x狀態(tài)轉(zhuǎn)化為成功態(tài)就遞歸調(diào)用resolvePromise}, reject);} else { //此分支存在的意義在于若executor調(diào)用resolve/reject不是異步的且不在resolve/reject中設(shè)置setTimeout,意味著當(dāng)new的時(shí)候就會返回一個(gè)帶狀態(tài)的promise就會走這里。x.then(resolve, reject); //2.3.2.2-2.3.2.3 //只要x狀態(tài)改變,就以x的狀態(tài)和值來改變promise2的狀態(tài)和值 //這個(gè)值可能是一個(gè)promise,前提是在上面那種假設(shè)實(shí)現(xiàn)中 //如果不符合上面那種實(shí)現(xiàn)且不想像規(guī)范一樣允許值可以為一個(gè)promise或則對象 可除去此分支}} else if (x != null && ((typeof x === 'function') || (typeof x === 'object'))) { //2.3.3.try {let then = x.then; //2.3.3.1if (typeof then === 'function') {//2.3.3.3.then.call(x, (y) => {if (called) return; //2.3.3.3.3.called = true;resolvePromise(promise2, y, resolve, reject); //在resolve中又包含promise的情況下,由于resolve中的 value.then存在,當(dāng)前回調(diào)調(diào)用時(shí),resolve中的promise狀態(tài)一定已經(jīng)改變,在狀態(tài)已經(jīng)改變的時(shí)候利用then綁定回調(diào),會走then中的status==fulfilled或則rejected分支}, (reason) => {if (called) return;called = true;reject(reason);});} else {resolve(x); //2.3.3.4. //1.3}} catch (e) {if (called) return; //2.3.3.3.4.1.called = true;reject(e); //2.3.3.2. //2.3.3.3.4.2.}} else { //2.3.4.resolve(x);} }Promise.deferred = Promise.defer = function () {let defer = {};defer.promise = new Promise(function (resolve, reject) {defer.resolve = resolve;defer.reject = reject;});return defer; };Promise.prototype.catch = function (onRejected) {this.then(null, onRejected) };Promise.resolve = function (value) {return new Promise((resolve, reject) => {resolve(value);}) };Promise.reject = function (reason) {return new Promise((resolve, reject) => {reject(reason);}) };Promise.all = function(promises){return new Promise((resolve,reject)=>{let result = [];let count = 0;function done(i,data){result[i] = data;if(++count === promises.length){resolve(result);}}for(let i=0;i<promises.length;++i){promises[i].then((value)=>{done(i,value);},reject);}}) };Promise.race = function(promises){return new Promise(function(resolve,reject){for(let i=0;i<promises.length;++i){promises[i].then(resolve,reject);}}); };Promise.promisify = function(fn){return function(...args){return new Promise((resolve,reject)=>{fn.apply(null,[...args,function(err,data){err?reject(err):resolve(data);}]);});} };Promise.promisifyALL = function(obj){for(var key in obj){if(obj.hasOwnProperty(key)&&typeof obj[key]=='function'){obj[key+'Async'] = Promise.promisify(obj[key]);}} }; module.exports = Promise; 復(fù)制代碼

總結(jié)

以上是生活随笔為你收集整理的Promise深度学习---我のPromise/A+实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。