JavaScript Promise原理與實(shí)現(xiàn)刨析
1 Promise核心邏輯實(shí)現(xiàn)
Promise對(duì)象是一個(gè)原生的javascript對(duì)象,是一種異步編程的解決方案,它通過(guò)一個(gè)回調(diào),可以避免更多的回調(diào),接下來(lái)說(shuō)明其原理及實(shí)現(xiàn)。
下面一段代碼是Promise的基本使用:
new Promise((resolve, reject) => {
resolve("成功");
reject("失敗");
})
Promise.then(value => { }, reason => { })
從上面的代碼中,我們可以分析出一些關(guān)鍵點(diǎn):
- Promise創(chuàng)建時(shí)需要使用
new關(guān)鍵字,那么我們可以知道Promise就是一個(gè)類(lèi); - 在執(zhí)行這個(gè)類(lèi)的時(shí)候,需要傳遞一個(gè)執(zhí)行器進(jìn)去,這個(gè)執(zhí)行器會(huì)立即執(zhí)行;
- 在執(zhí)行器中有兩個(gè)參數(shù),
resolve和reject,它們都是函數(shù),用來(lái)改變Promise中的狀態(tài); - Promise中有三種狀態(tài),分別是:成功
fulfilled、失敗rejected和等待pending,狀態(tài)只能從pending—>fulfilled,或者pending—>rejected,狀態(tài)一旦確定就不可以更改; resolve和reject函數(shù)是用來(lái)更改狀態(tài)的,其中,resolve將狀態(tài)更改為fulfilled,reject將狀態(tài)更改為rejected;then方法接收兩個(gè)函數(shù)作為參數(shù),它需要判斷狀態(tài),如果成功調(diào)用第一個(gè)回調(diào)函數(shù),如果失敗調(diào)用第二個(gè)回調(diào)函數(shù),并且then方法是被定義在原型對(duì)象中的,第一個(gè)回調(diào)函數(shù)的參數(shù)為成功之后的值,第二個(gè)回調(diào)函數(shù)的參數(shù)為失敗之后的原因;
接下來(lái)我們根據(jù)上面分析出的內(nèi)容,一步一步實(shí)現(xiàn)我們自己的Promise。
首先創(chuàng)建一個(gè)類(lèi),為constructor構(gòu)造函數(shù)傳入一個(gè)執(zhí)行器,因?yàn)閳?zhí)行器需要立即執(zhí)行,因此在構(gòu)造函數(shù)中調(diào)用該執(zhí)行器。
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
executor(); // 執(zhí)行器會(huì)立即執(zhí)行
}
}
在執(zhí)行器中有兩個(gè)參數(shù)resolve和reject,它們都是函數(shù),因此在類(lèi)中創(chuàng)建兩個(gè)箭頭函數(shù)resolve和reject,在執(zhí)行器executor中使用this來(lái)調(diào)用它們。
為什么使用箭頭函數(shù):
注意,我們?cè)赑romise中調(diào)用resolve和reject是直接調(diào)用的,如果將它們寫(xiě)成普通函數(shù),那么會(huì)將this指向window或者undefined,如果我們寫(xiě)成箭頭函數(shù),那么它們的this就會(huì)指向類(lèi)的實(shí)例對(duì)象。
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
}
resolve = () => {
}
reject = () => {
}
}
resolve和reject這兩個(gè)函數(shù)是用來(lái)改變狀態(tài)的,因此我們將狀態(tài)定義在類(lèi)的外面,因?yàn)樗鼈儠?huì)被頻繁使用到。在類(lèi)中我們默認(rèn)定義狀態(tài)status是等待pending,當(dāng)調(diào)用resolve時(shí),狀態(tài)改為成功,當(dāng)調(diào)用reject時(shí),狀態(tài)改為失敗。并且狀態(tài)一旦確定不可更改,因此我們要在兩個(gè)函數(shù)中判斷當(dāng)前狀態(tài)是否為等待,不是則返回。
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
resolve = () => {
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
}
reject = () => {
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
}
}Promise中的then方法有兩個(gè)參數(shù),當(dāng)狀態(tài)成功調(diào)用第一個(gè),狀態(tài)失敗調(diào)用第二個(gè),因此內(nèi)部需要使用if來(lái)判斷狀態(tài)。調(diào)用成功或者失敗函數(shù)時(shí),需要為其傳入?yún)?shù),那么我們知道成功的值是由resolve傳遞來(lái)的,失敗的原因是由reject傳遞來(lái)的,因此我們?cè)赑romise中聲明兩個(gè)屬性存放兩個(gè)值。
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
value = undefined; // 成功之后的值
reason = undefined; // 失敗之后的原因
resolve = value => { // value是成功之后的值
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
this.value = value; // 將成功的值傳遞
}
reject = reason => { // reason是失敗之后的原因
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
this.reason = reason; // 將失敗的值傳遞
}
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
successCallback(this.value);
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
failCallback(this.reason);
}
}
}到這里我們就實(shí)現(xiàn)了一個(gè)最簡(jiǎn)單的Promise了。
2 加入異步邏輯
上面我們實(shí)現(xiàn)的Promise,實(shí)際上并沒(méi)有考慮異步情況,比如說(shuō)下面的代碼中,2秒后調(diào)用成功的回調(diào),如果這時(shí)調(diào)用then方法,那么當(dāng)前的狀態(tài)是等待pending,但是我們并沒(méi)有判斷狀態(tài)是pending時(shí)的情況。
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("成功");
}, 2000);
})
Promise.then(value => { }, reason => { })
因此在then方法中,我們應(yīng)該判斷當(dāng)狀態(tài)是等待的情況。當(dāng)狀態(tài)是等待時(shí),我們沒(méi)有辦法調(diào)用成功或者失敗的回調(diào),這時(shí)我們需要將成功回調(diào)和失敗回調(diào)儲(chǔ)存起來(lái)。
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
value = undefined; // 成功之后的值
reason = undefined; // 失敗之后的原因
successCallback = undefined; // 成功的回調(diào)函數(shù)
failCallback = undefined; // 失敗的回調(diào)函數(shù)
resolve = value => { // value是成功之后的值
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
this.value = value; // 將成功的值傳遞
}
reject = reason => { // reason是失敗之后的原因
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
this.reason = reason; // 將失敗的值傳遞
}
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
successCallback(this.value);
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
failCallback(this.reason);
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback = successCallback;
this.failCallback = failCallback;
}
}
}將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)之后,我們則要在resolve和reject方法中判斷是否存在成功或者失敗的回調(diào),如果存在,則將其調(diào)用。
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
value = undefined; // 成功之后的值
reason = undefined; // 失敗之后的原因
successCallback = undefined; // 成功的回調(diào)函數(shù)
failCallback = undefined; // 失敗的回調(diào)函數(shù)
resolve = value => { // value是成功之后的值
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
this.value = value; // 將成功的值傳遞
this.successCallback && this.successCallback(this.value); // 如果成功回調(diào)存在,則調(diào)用
}
reject = reason => { // reason是失敗之后的原因
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
this.reason = reason; // 將失敗的值傳遞
this.failCallback && this.failCallback(this.reason); // 如果失敗回調(diào)存在,則調(diào)用
}
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
successCallback(this.value);
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
failCallback(this.reason);
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback = successCallback;
this.failCallback = failCallback;
}
}
}這是我們就處理了異步的情況了。
3 then方法添加多次調(diào)用邏輯
Promise的then方法可以調(diào)用多次,我們接著處理這部分。
let promise = new Promise((resolve, reject) => { })
promise.then(value => { })
promise.then(value => { })
promise.then(value => { })如果多次調(diào)用了then方法,就需要考慮兩種情況:同步情況和異步情況。如果是同步情況,那么直接就可以調(diào)用回調(diào)函數(shù),我們已經(jīng)不需要多做處理了,如果是異步情況,那么我們需要將每一個(gè)回調(diào)函數(shù)儲(chǔ)存起來(lái)。
我們之前在then方法中判斷等待的時(shí)候,也將成功和失敗的回調(diào)存儲(chǔ)起來(lái),但是每次只能存儲(chǔ)一個(gè),因此我們需要將存儲(chǔ)的容器設(shè)為數(shù)組,通過(guò)數(shù)組的push方法將回調(diào)函數(shù)存儲(chǔ)起來(lái)。
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
value = undefined; // 成功之后的值
reason = undefined; // 失敗之后的原因
successCallback = []; // 使用數(shù)組存儲(chǔ)成功的回調(diào)函數(shù)
failCallback = []; // 使用數(shù)組存儲(chǔ)失敗的回調(diào)函數(shù)
resolve = value => { // value是成功之后的值
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
this.value = value; // 將成功的值傳遞
this.successCallback && this.successCallback(this.value); // 如果成功回調(diào)存在,則調(diào)用
}
reject = reason => { // reason是失敗之后的原因
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
this.reason = reason; // 將失敗的值傳遞
this.failCallback && this.failCallback(this.reason); // 如果失敗回調(diào)存在,則調(diào)用
}
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
successCallback(this.value);
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
failCallback(this.reason);
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
}
}更改成數(shù)組之后,那么我們?cè)瓉?lái)在resolve和reject函數(shù)中調(diào)用成功或者失敗的回調(diào)函數(shù)就不可以使用了,而是在其中循環(huán)調(diào)用數(shù)組中的回調(diào)函數(shù)。
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
value = undefined; // 成功之后的值
reason = undefined; // 失敗之后的原因
successCallback = []; // 成功的回調(diào)函數(shù)
failCallback = []; // 失敗的回調(diào)函數(shù)
resolve = value => { // value是成功之后的值
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
this.value = value; // 將成功的值傳遞
while (this.successCallback.length) { // 循環(huán)執(zhí)行數(shù)組中的回調(diào)函數(shù)
this.successCallback.shift()(this.value); // 調(diào)用回調(diào)函數(shù)
}
}
reject = reason => { // reason是失敗之后的原因
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
this.reason = reason; // 將失敗的值傳遞
while (this.failCallback.length) { // 循環(huán)執(zhí)行
this.failCallback.shift()(this.value); // 調(diào)用失敗回調(diào)函數(shù)
}
}
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
successCallback(this.value);
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
failCallback(this.reason);
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
}
}4 鏈?zhǔn)秸{(diào)用then方法
Promise的then方法可以鏈?zhǔn)秸{(diào)用,下一個(gè)then方法中成功回調(diào)函數(shù)的參數(shù)是上一個(gè)then方法中的回調(diào)函數(shù)的返回值,也就是說(shuō),在下面代碼中,value的值為1。
let promise = new Promise((resolve, reject) => { });
promise.then(() => { return 1 })
.then(value => { })
.then(() => { })我們首先來(lái)實(shí)現(xiàn)then方法的鏈?zhǔn)秸{(diào)用。then方法是Promise中的方法,如果要實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用,那么每個(gè)then方法都應(yīng)該返回一個(gè)Promise對(duì)象,這樣才可以調(diào)用。那么我們應(yīng)該在then方法中創(chuàng)建一個(gè)Promise對(duì)象,最后返回這個(gè)對(duì)象就可以。除此之外,我們還需要將then方法中原來(lái)的代碼傳入到新創(chuàng)建對(duì)象的執(zhí)行器中,保證調(diào)用方法后就立即執(zhí)行。
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
let promise = new MyPromise(() => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
successCallback(this.value);
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
failCallback(this.reason);
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
})
return promise;
}那么鏈?zhǔn)秸{(diào)用的問(wèn)題就解決了,我們還需要將本次回調(diào)函數(shù)的返回值傳到下一個(gè)then的成功回調(diào)函數(shù)中。因此,我們需要獲取到成功和失敗回調(diào)函數(shù)的返回值,并將其通過(guò)新promise對(duì)象的resolve方法傳遞過(guò)去。
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
let result = successCallback(this.value);
resolve(result); // 將返回值傳遞到下一個(gè)回調(diào)函數(shù)
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
let result = failCallback(this.reason);
resolve(result);
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
})
return promise;
}如果上一次回調(diào)函數(shù)的返回值是一個(gè)Promise對(duì)象,我們就需要查看Promise對(duì)象的狀態(tài),如果狀態(tài)成功,則調(diào)用resolve將狀態(tài)傳遞給下一個(gè)Promise對(duì)象,如果狀態(tài)失敗,則調(diào)用reject將失敗信息傳遞。我們需要寫(xiě)一個(gè)方法resolvePromise,用來(lái)判斷這些邏輯。
function resolvePromise(result, resolve, reject) {
// 通過(guò)判斷result是不是MyPromise的實(shí)例對(duì)象來(lái)判斷是不是Promise對(duì)象
if (result instanceof MyPromise) { // 是Promise對(duì)象
// 調(diào)用then方法查看Promise對(duì)象的狀態(tài)
// 如果成功調(diào)用第一個(gè)回調(diào)函數(shù),如果失敗調(diào)用第二個(gè)回調(diào)函數(shù)
result.then(value => resolve(value), reason => reject(reason));
} else { // 如果是普通值
resolve(result); // 直接將普通值傳遞
}
}那么在then方法中調(diào)用resolvePromise函數(shù):
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
let result = successCallback(this.value);
resolvePromise(result, resolve, reject); // 調(diào)用方法
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
let result = failCallback(this.reason);
resolvePromise(result, resolve, reject);
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
})
return promise;
}在上面我們知道then方法中可以返回Promise對(duì)象,那么如果返回的Promise對(duì)象還是then方法中接收到的Promise對(duì)象,則會(huì)形成循環(huán)調(diào)用,這時(shí)應(yīng)該報(bào)出錯(cuò)誤。我們?cè)?code>then方法中拿到了返回值result,因此只需要判斷它是不是和promise相同即可。我們將這個(gè)邏輯也寫(xiě)在resolvePromise函數(shù)中。
function resolvePromise(promise, result, resolve, reject) {
if (promise === result) { // 如果相同,報(bào)錯(cuò)
reject(new TypeError("promise對(duì)象循環(huán)了"));
return; // 阻止代碼向下執(zhí)行
}
// 通過(guò)判斷result是不是MyPromise的實(shí)例對(duì)象來(lái)判斷是不是Promise對(duì)象
if (result instanceof MyPromise) { // 是Promise對(duì)象
// 調(diào)用then方法查看Promise對(duì)象的狀態(tài)
// 如果成功調(diào)用第一個(gè)回調(diào)函數(shù),如果失敗調(diào)用第二個(gè)回調(diào)函數(shù)
result.then(value => resolve(value), reason => reject(reason));
} else { // 如果是普通值
resolve(result); // 直接將普通值傳遞
}
}then方法中也調(diào)用上面的函數(shù)。但是實(shí)際上我們?cè)?code>then方法中是獲取不到promise的,因?yàn)?code>promise在實(shí)例化之后才可以獲取到,這時(shí)我們可以將狀態(tài)成功時(shí)的代碼變成異步代碼,讓同步代碼先執(zhí)行完成,執(zhí)行完成之后再執(zhí)行異步代碼。我們可以使用setTimeout定時(shí)器來(lái)使其變成異步代碼。
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
}, 0)
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
setTimeout(() => {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
}, 0)
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
})
return promise;
}全部代碼如下:
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
try {
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
} catch (e) {
this.reject(e); // 將錯(cuò)誤原因傳遞給失敗回調(diào)函數(shù)
}
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
value = undefined; // 成功之后的值
reason = undefined; // 失敗之后的原因
successCallback = []; // 成功的回調(diào)函數(shù)
failCallback = []; // 失敗的回調(diào)函數(shù)
resolve = value => { // value是成功之后的值
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
this.value = value; // 將成功的值傳遞
// this.successCallback && this.successCallback(this.value); // 如果成功回調(diào)存在,則調(diào)用
while (this.successCallback.length) { // 循環(huán)執(zhí)行數(shù)組中的回調(diào)函數(shù)
this.successCallback.shift()(this.value); // 調(diào)用回調(diào)函數(shù)
}
}
reject = reason => { // reason是失敗之后的原因
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
this.reason = reason; // 將失敗的值傳遞
// this.failCallback && this.failCallback(this.reason); // 如果失敗回調(diào)存在,則調(diào)用
while (this.failCallback.length) { // 循環(huán)執(zhí)行
this.failCallback.shift()(this.value); // 調(diào)用失敗回調(diào)函數(shù)
}
}
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
}, 0)
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
setTimeout(() => {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
}, 0)
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
})
return promise;
}
}
function resolvePromise(promise, result, resolve, reject) {
if (promise === result) { // 如果相同,報(bào)錯(cuò)
reject(new TypeError("promise對(duì)象循環(huán)了"));
return; // 阻止代碼向下執(zhí)行
}
// 通過(guò)判斷result是不是MyPromise的實(shí)例對(duì)象來(lái)判斷是不是Promise對(duì)象
if (result instanceof MyPromise) { // 是Promise對(duì)象
// 調(diào)用then方法查看Promise對(duì)象的狀態(tài)
// 如果成功調(diào)用第一個(gè)回調(diào)函數(shù),如果失敗調(diào)用第二個(gè)回調(diào)函數(shù)
result.then(value => resolve(value), reason => reject(reason));
} else { // 如果是普通值
resolve(result); // 直接將普通值傳遞
}
}5 Promise錯(cuò)誤捕獲
1、捕獲執(zhí)行器錯(cuò)誤。當(dāng)執(zhí)行器錯(cuò)誤時(shí),直接執(zhí)行reject方法,這個(gè)錯(cuò)誤實(shí)際上是在then方法中的失敗回調(diào)函數(shù)中輸出的。
constructor(executor) { // 接收一個(gè)執(zhí)行器
try {
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
} catch (e) {
this.reject(e); // 將錯(cuò)誤原因傳遞給失敗回調(diào)函數(shù)
}
}
2、捕獲then方法中回調(diào)函數(shù)的錯(cuò)誤。如果當(dāng)前then方法中的回調(diào)函數(shù)錯(cuò)誤,那么應(yīng)該在下一個(gè)then方法中的失敗回調(diào)函數(shù)中輸出。
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
}
})
return promise;
}
當(dāng)狀態(tài)為等待時(shí),也需要為它進(jìn)行錯(cuò)誤處理。狀態(tài)為等待時(shí),數(shù)組中原本存入了成功和失敗的回調(diào),但是這樣沒(méi)有辦法進(jìn)行錯(cuò)誤處理,因此我們可以在數(shù)組中存入一個(gè)回調(diào)函數(shù),回調(diào)函數(shù)內(nèi)部調(diào)用成功或者失敗的函數(shù)。
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(() => { // 為數(shù)組添加成功回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
});
this.failCallback.push(() => { // 為數(shù)組添加失敗回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
});
}
})
return promise;
}那么在resolve和reject函數(shù)中,調(diào)用成功和失敗函數(shù)的邏輯也需要修改一下:
// 局部代碼 this.successCallback.shift()(); // 調(diào)用回調(diào)函數(shù) this.failCallback.shift()(); // 調(diào)用失敗回調(diào)函數(shù)
全部代碼:
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
try {
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
} catch (e) {
this.reject(e); // 將錯(cuò)誤原因傳遞給失敗回調(diào)函數(shù)
}
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
value = undefined; // 成功之后的值
reason = undefined; // 失敗之后的原因
successCallback = []; // 成功的回調(diào)函數(shù)
failCallback = []; // 失敗的回調(diào)函數(shù)
resolve = value => { // value是成功之后的值
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
this.value = value; // 將成功的值傳遞
// this.successCallback && this.successCallback(this.value); // 如果成功回調(diào)存在,則調(diào)用
while (this.successCallback.length) { // 循環(huán)執(zhí)行數(shù)組中的回調(diào)函數(shù)
this.successCallback.shift()(); // 調(diào)用回調(diào)函數(shù)
}
}
reject = reason => { // reason是失敗之后的原因
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
this.reason = reason; // 將失敗的值傳遞
// this.failCallback && this.failCallback(this.reason); // 如果失敗回調(diào)存在,則調(diào)用
while (this.failCallback.length) { // 循環(huán)執(zhí)行
this.failCallback.shift()(); // 調(diào)用失敗回調(diào)函數(shù)
}
}
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(() => { // 為數(shù)組添加成功回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
});
this.failCallback.push(() => { // 為數(shù)組添加失敗回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
});
}
})
return promise;
}
}
function resolvePromise(promise, result, resolve, reject) {
if (promise === result) { // 如果相同,報(bào)錯(cuò)
reject(new TypeError("promise對(duì)象循環(huán)了"));
return; // 阻止代碼向下執(zhí)行
}
// 通過(guò)判斷result是不是MyPromise的實(shí)例對(duì)象來(lái)判斷是不是Promise對(duì)象
if (result instanceof MyPromise) { // 是Promise對(duì)象
// 調(diào)用then方法查看Promise對(duì)象的狀態(tài)
// 如果成功調(diào)用第一個(gè)回調(diào)函數(shù),如果失敗調(diào)用第二個(gè)回調(diào)函數(shù)
result.then(value => resolve(value), reason => reject(reason));
} else { // 如果是普通值
resolve(result); // 直接將普通值傳遞
}
}6 then方法參數(shù)設(shè)置為可選
如果then方法中沒(méi)有參數(shù),那么它的參數(shù)應(yīng)該傳到之后的then方法中。
let p = new Promise((resolve, reject) => { resolve(100) })
p.then().then().then(value => console.log(value)); // 100
那么我們可以在then方法中判斷是否傳入了參數(shù),如果沒(méi)有直接傳到下一個(gè)then方法中。
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
// 如果沒(méi)有傳入?yún)?shù),則將值返回
successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => reason => { throw reason };
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(() => { // 為數(shù)組添加成功回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
});
this.failCallback.push(() => { // 為數(shù)組添加失敗回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
});
}
})
return promise;
}7 實(shí)現(xiàn)Promise.all
Promise.all方法接收一個(gè)數(shù)組作為參數(shù),它允許我們按照異步代碼調(diào)用的順序得到異步代碼的結(jié)果,也就是說(shuō),它的輸出結(jié)果就是參數(shù)的傳遞順序。這個(gè)方法有幾點(diǎn)需要注意:
Promise.all方法的返回值也是一個(gè)Promise對(duì)象,也就是說(shuō),它也可以鏈?zhǔn)秸{(diào)用then方法;- 當(dāng)
Promise.all中所有結(jié)果都是成功的,那么結(jié)果就是成功的,如果有一個(gè)結(jié)果是失敗的,那么它就是失敗的;
Promise.all(["a", "b", p1(), p2(), "c"]).then(result => {
// result -> ["a", "b", p1(), p2(), "c"]
})
首先,我們看到all方法是Promise類(lèi)名直接調(diào)用的,說(shuō)明它是一個(gè)靜態(tài)方法。它接受了一個(gè)數(shù)組作為參數(shù),最終返回了一個(gè)Promise對(duì)象,那么基本框架我們可以寫(xiě)出來(lái)了:
static all(array) {
return new MyPromise((resolve, reject) => {
})
}
接著我們應(yīng)該判斷傳入的參數(shù)是普通值還是Promise對(duì)象,如果是普通值,那么直接放到結(jié)果數(shù)組中,如果是Promise對(duì)象,那么我們就先執(zhí)行這個(gè)Promise對(duì)象,再將執(zhí)行后的結(jié)果放到結(jié)果數(shù)組當(dāng)中。將結(jié)果添加到結(jié)果數(shù)組中時(shí),我們定義一個(gè)函數(shù)addData來(lái)幫助我們。當(dāng)循環(huán)執(zhí)行完成之后,我們應(yīng)該調(diào)用resolve方法將result結(jié)果數(shù)組傳遞到外面。
static all(array) {
let result = []; // 結(jié)果數(shù)組,用來(lái)存放結(jié)果
function addData(key, value) { // 將結(jié)果添加到結(jié)果數(shù)組中
result[key] = value;
}
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
let current = array[i]; // 獲取當(dāng)前的值
if (current instanceof MyPromise) { // 是一個(gè)Promise對(duì)象
// 如果是一個(gè)Promise對(duì)象,我們首先要執(zhí)行這個(gè)對(duì)象
// 調(diào)用它的then方法,如果成功將結(jié)果添加到數(shù)組中,失敗則傳遞錯(cuò)誤
current.then(value => addData(i, value), reason => reject(reason))
} else { // 是一個(gè)普通值
addData(i, array[i]); // 普通值直接將結(jié)果添加到數(shù)組中
}
}
resolve(result); // 將結(jié)果傳遞出去
})
}但是這里會(huì)出現(xiàn)一個(gè)問(wèn)題,for循環(huán)是一瞬間執(zhí)行完成了,如果Promise中有異步代碼,那么異步代碼并沒(méi)有執(zhí)行完就執(zhí)行resolve方法,那么我們最終拿不到異步任務(wù)的結(jié)果。所以我們可以設(shè)置一個(gè)計(jì)數(shù)器index,當(dāng)結(jié)果數(shù)組中有一個(gè)結(jié)果,就讓計(jì)數(shù)器+1,當(dāng)計(jì)數(shù)器的值等于數(shù)組array的長(zhǎng)度時(shí),才能執(zhí)行resolve方法。
static all(array) {
let result = []; // 結(jié)果數(shù)組,用來(lái)存放結(jié)果
let index = 0; // 計(jì)數(shù)器,記錄是否執(zhí)行完成
return new MyPromise((resolve, reject) => {
// addData方法在數(shù)組中才能執(zhí)行resolve
function addData(key, value) { // 將結(jié)果添加到結(jié)果數(shù)組中
result[key] = value;
index++;
if (index === array.length) resolve(result);
}
for (let i = 0; i < array.length; i++) {
let current = array[i]; // 獲取當(dāng)前的值
if (current instanceof MyPromise) { // 是一個(gè)Promise對(duì)象
// 如果是一個(gè)Promise對(duì)象,我們首先要執(zhí)行這個(gè)對(duì)象
// 調(diào)用它的then方法,如果成功將結(jié)果添加到數(shù)組中,失敗則傳遞錯(cuò)誤
current.then(value => addData(i, value), reason => reject(reason))
} else { // 是一個(gè)普通值
addData(i, array[i]); // 普通值直接將結(jié)果添加到數(shù)組中
}
}
})
}8 實(shí)現(xiàn)Promise.resolve
Promise.resolve方法會(huì)將給定的值轉(zhuǎn)換成Promise對(duì)象,也就是說(shuō)它的返回值就是一個(gè)Promise對(duì)象。
Promise.resolve(10).then(value => console.log(value));
Promise.resolve方法是一個(gè)靜態(tài)方法,在該方法內(nèi)部會(huì)判斷參數(shù)是否為Promise對(duì)象,如果是,則原封不動(dòng)返回,如果不是,就創(chuàng)建一個(gè)Promise對(duì)象,將給定的值包裹在Promise對(duì)象當(dāng)中,最后返回即可。
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
}9 實(shí)現(xiàn)Promise.race
Promise.race參數(shù)是數(shù)組,它會(huì)返回一個(gè)Promise對(duì)象,一旦某個(gè)參數(shù)先改變狀態(tài),那么直接就將該狀態(tài)返回,也就是說(shuō),看誰(shuí)執(zhí)行的更快。
Promise.race(["a", "b", "c"]).then(value => console.log(value));
Promise.race方法是一個(gè)靜態(tài)方法,它接受一個(gè)數(shù)組作為參數(shù),最后返回一個(gè)Promise對(duì)象,基礎(chǔ)框架如下:
static race(array) {
return new MyPromise((reslve, reject) => { })
}
循環(huán)遍歷參數(shù),返回第一個(gè)成功或者失敗的結(jié)果。
static race(array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
Promise.resolve(array[i]).then(value => resolve(value), reason => reject(reason));
}
})
}
10 實(shí)現(xiàn)finally方法
finally方法接受一個(gè)回調(diào)函數(shù)作為參數(shù),它有一些特點(diǎn):
- 無(wú)論最后Promise對(duì)象最終的狀態(tài)是成功的還是失敗的,該方法中回調(diào)函數(shù)都會(huì)被執(zhí)行一次
finally方法后可以鏈?zhǔn)秸{(diào)用then方法拿到當(dāng)前Promise對(duì)象最終返回的結(jié)果。
let promise = new Promise();
promise.finally(() => console.log("finally")).then(value => console.log(value));
首先我們要獲得Promise對(duì)象的狀態(tài),我們可以調(diào)用then方法來(lái)獲得狀態(tài)。由于無(wú)論狀態(tài)成功還是失敗,我們都要調(diào)用回調(diào)函數(shù),因此在then方法中成功和失敗中都調(diào)用一次該回調(diào)函數(shù)。由于finally返回Promise對(duì)象,then方法也返回Promise對(duì)象,因此我們直接將then方法返回即可。
finally(callBack) {
return this.then(() => {
callBack(); // 成功的回調(diào)函數(shù)中調(diào)用
}, () => {
callBack(); // 失敗的回調(diào)函數(shù)中調(diào)用
})
}
接著,我們需要在成功的回調(diào)函數(shù)中返回成功的值,在失敗的回調(diào)函數(shù)中傳遞失敗的原因。
finally(callBack) {
return this.then(value => {
callBack(); // 成功的回調(diào)函數(shù)中調(diào)用
return value; // 將成功的值返回
}, reason => {
callBack(); // 失敗的回調(diào)函數(shù)中調(diào)用
throw reason; // 將失敗原因傳遞下去
})
}
如果在finally后面的then中返回了一個(gè)Promise對(duì)象,對(duì)象中有異步代碼,那么我們應(yīng)該等待異步代碼執(zhí)行完成之后,再繼續(xù)執(zhí)行后面的then方法。所以我們應(yīng)該判斷callBack的返回值是什么,如果是一個(gè)普通值,我們將其轉(zhuǎn)換為Promise對(duì)象,等待其執(zhí)行完成,如果是一個(gè)Promise對(duì)象,我們還是等待其執(zhí)行完成。
finally(callBack) {
return this.then(value => {
return MyPromise.resolve(callBack()).then(() => value);
}, reason => {
return MyPromise.resolve(callBack()).then(() => { throw reason });
})
}
11 實(shí)現(xiàn)catch方法
catch方法用來(lái)處理Promise對(duì)象最終為失敗的情況,當(dāng)我們調(diào)用then方法是,是可以不傳遞失敗回調(diào)的,那么失敗回調(diào)會(huì)被catch方法所捕獲。
let promise = new Promise(); promise.then(value => console.log(value)).catch(reason => console.log(reason));
catch方法接受一個(gè)回調(diào)函數(shù)作為參數(shù),在其內(nèi)部調(diào)用then方法,并且不傳遞成功回調(diào),只傳遞失敗回調(diào)函數(shù),最后將then方法返回即可。
catch(failCallback) {
return this.then(undefined, failCallback);
}
12 全部代碼展示
const PENDING = "pending"; // 等待
const FULFILLED = "fulfilled"; // 成功
const REJECTED = "rejected"; // 失敗
class MyPromise {
constructor(executor) { // 接收一個(gè)執(zhí)行器
try {
executor(this.resolve, this.reject); // 執(zhí)行器會(huì)立即執(zhí)行
} catch (e) {
this.reject(e); // 將錯(cuò)誤原因傳遞給失敗回調(diào)函數(shù)
}
}
status = PENDING; // 狀態(tài)默認(rèn)為pending等待
value = undefined; // 成功之后的值
reason = undefined; // 失敗之后的原因
successCallback = []; // 成功的回調(diào)函數(shù)
failCallback = []; // 失敗的回調(diào)函數(shù)
resolve = value => { // value是成功之后的值
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = FULFILLED; // 將狀態(tài)改為成功
this.value = value; // 將成功的值傳遞
// this.successCallback && this.successCallback(this.value); // 如果成功回調(diào)存在,則調(diào)用
while (this.successCallback.length) { // 循環(huán)執(zhí)行數(shù)組中的回調(diào)函數(shù)
this.successCallback.shift()(); // 調(diào)用回調(diào)函數(shù)
}
}
reject = reason => { // reason是失敗之后的原因
if (this.status !== PENDING) return; // 當(dāng)狀態(tài)不是等待,直接返回
this.status = REJECTED; // 將狀態(tài)改為失敗
this.reason = reason; // 將失敗的值傳遞
// this.failCallback && this.failCallback(this.reason); // 如果失敗回調(diào)存在,則調(diào)用
while (this.failCallback.length) { // 循環(huán)執(zhí)行
this.failCallback.shift()(); // 調(diào)用失敗回調(diào)函數(shù)
}
}
then(successCallback, failCallback) { // then方法有兩個(gè)參數(shù)
// 如果沒(méi)有傳入?yún)?shù),則將值返回
successCallback = successCallback ? successCallback : value => value;
failCallback = failCallback ? failCallback : reason => { throw reason };
let promise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) { // 成功調(diào)用第一個(gè)回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
} else if (this.status === REJECTED) { // 失敗調(diào)用第二個(gè)回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
} else { // 當(dāng)狀態(tài)為等待時(shí),將成功回調(diào)和失敗回調(diào)存儲(chǔ)起來(lái)
this.successCallback.push(() => { // 為數(shù)組添加成功回調(diào)函數(shù)
setTimeout(() => { // 變成異步代碼,獲取promise
try {
let result = successCallback(this.value);
resolvePromise(promise, result, resolve, reject); // 調(diào)用方法
} catch (e) {
reject(e); // 將錯(cuò)誤傳遞到下一個(gè)then中
}
}, 0)
});
this.failCallback.push(() => { // 為數(shù)組添加失敗回調(diào)函數(shù)
setTimeout(() => {
try {
let result = failCallback(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e); // 傳遞錯(cuò)誤
}
}, 0)
});
}
})
return promise;
}
finally(callBack) {
return this.then(value => {
return MyPromise.resolve(callBack()).then(() => value);
}, reason => {
return MyPromise.resolve(callBack()).then(() => { throw reason });
})
}
catch(failCallback) {
return this.then(undefined, failCallback);
}
static all(array) {
let result = []; // 結(jié)果數(shù)組,用來(lái)存放結(jié)果
let index = 0; // 計(jì)數(shù)器,記錄是否執(zhí)行完成
return new MyPromise((resolve, reject) => {
function addData(key, value) { // 將結(jié)果添加到結(jié)果數(shù)組中
result[key] = value;
index++;
if (index === array.length) resolve(result);
}
for (let i = 0; i < array.length; i++) {
let current = array[i]; // 獲取當(dāng)前的值
if (current instanceof MyPromise) { // 是一個(gè)Promise對(duì)象
// 如果是一個(gè)Promise對(duì)象,我們首先要執(zhí)行這個(gè)對(duì)象
// 調(diào)用它的then方法,如果成功將結(jié)果添加到數(shù)組中,失敗則傳遞錯(cuò)誤
current.then(value => addData(i, value), reason => reject(reason))
} else { // 是一個(gè)普通值
addData(i, array[i]); // 普通值直接將結(jié)果添加到數(shù)組中
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
}
static race(array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
Promise.resolve(array[i]).then(value => resolve(value), reason => reject(reason));
}
})
}
}
function resolvePromise(promise, result, resolve, reject) {
if (promise === result) { // 如果相同,報(bào)錯(cuò)
reject(new TypeError("promise對(duì)象循環(huán)了"));
return; // 阻止代碼向下執(zhí)行
}
// 通過(guò)判斷result是不是MyPromise的實(shí)例對(duì)象來(lái)判斷是不是Promise對(duì)象
if (result instanceof MyPromise) { // 是Promise對(duì)象
// 調(diào)用then方法查看Promise對(duì)象的狀態(tài)
// 如果成功調(diào)用第一個(gè)回調(diào)函數(shù),如果失敗調(diào)用第二個(gè)回調(diào)函數(shù)
result.then(value => resolve(value), reason => reject(reason));
} else { // 如果是普通值
resolve(result); // 直接將普通值傳遞
}
}到此這篇關(guān)于JavaScript Promise原理與實(shí)現(xiàn)刨析的文章就介紹到這了,更多相關(guān)JS Promise內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript設(shè)計(jì)模式 – 策略模式原理與用法實(shí)例分析
這篇文章主要介紹了javascript設(shè)計(jì)模式 – 策略模式,結(jié)合實(shí)例形式分析了javascript策略模式相關(guān)概念、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04
element-ui組件輸入框之放大鏡搜索圖標(biāo)問(wèn)題
這篇文章主要介紹了element-ui組件輸入框之放大鏡(搜索圖標(biāo))的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-11-11
JS使用隊(duì)列對(duì)數(shù)組排列,基數(shù)排序算法示例
這篇文章主要介紹了JS使用隊(duì)列對(duì)數(shù)組排列,基數(shù)排序算法,涉及javascript隊(duì)列的定義、使用,基數(shù)排序?qū)崿F(xiàn)方法等相關(guān)操作技巧,需要的朋友可以參考下2019-03-03
微信小程序webview中監(jiān)聽(tīng)返回按鈕實(shí)現(xiàn)步驟
在微信小程序中webview返回鍵是一個(gè)非常實(shí)用的功能,它允許用戶在嵌入的網(wǎng)頁(yè)中返回到上一個(gè)頁(yè)面,這篇文章主要給大家介紹了微信小程序webview中監(jiān)聽(tīng)返回按鈕的實(shí)現(xiàn)步驟,需要的朋友可以參考下2024-08-08
GWT中復(fù)制到剪貼板 js+flash實(shí)現(xiàn)復(fù)制 兼容性比較好
今天看到有個(gè)Google Code的項(xiàng)目,叫ZeroClipboard,大意是使用flash作為媒介,將內(nèi)容復(fù)制到剪貼板。這比用純javascript好,因?yàn)椴煌瑸g覽器會(huì)出于安全的原因,有不同反應(yīng),例如IE會(huì)給出提示,有的瀏覽器不支持復(fù)制到剪貼板。2010-03-03
JS匿名函數(shù)類(lèi)生成方式實(shí)例分析
這篇文章主要介紹了JS匿名函數(shù)類(lèi)生成方式,結(jié)合實(shí)例形式分析了javascript匿名函數(shù)類(lèi)相關(guān)屬性與方法定義與使用技巧,需要的朋友可以參考下2016-11-11

