Promise簡介
一個Promise
對象代表一個在這個 promise 被創(chuàng)建出來時不一定已知的值掀虎。它讓您能夠把異步操作最終的成功返回值或者失敗原因和相應的處理程序關(guān)聯(lián)起來徐矩。 這樣使得異步方法可以像同步方法那樣返回值:異步方法并不會立即返回最終的值,而是會返回一個 promise 叁幢,以便在未來某個時候把值交給使用者滤灯。
一個 Promise
必然處于以下幾種狀態(tài)之一:
- 待定(pending) : 初始狀態(tài),既沒有被兌現(xiàn)曼玩,也沒有被拒絕鳞骤。
- 已兌現(xiàn)(fulfilled) : 意味著操作成功完成。
- 已拒絕(rejected) : 意味著操作失敗黍判。
待定狀態(tài)的 Promise 對象要么會通過一個值被兌現(xiàn)(fulfilled) 豫尽,要么會通過一個原因(錯誤) 被拒絕(rejected) 。當這些情況之一發(fā)生時顷帖,我們用 promise 的 then 方法排列起來的相關(guān)處理程序就會被調(diào)用美旧。如果 promise 在一個相應的處理程序被綁定時就已經(jīng)被兌現(xiàn)或被拒絕了,那么這個處理程序就會被調(diào)用贬墩,因此在完成異步操作和綁定處理方法之間不會存在競爭狀態(tài)榴嗅。
因為 Promsie的then、catch和finally方法返回的是 promise陶舞, 所以它們可以被鏈式調(diào)用嗽测。
Promise實例的方法(設promise為Promise的實例)
promise.then(onFulfilled,onRejected)
onFulfilled(可選):將在promise的狀態(tài)變成fulfilled時調(diào)用,參數(shù)為promise成功的結(jié)果肿孵。如果onFulfilled的返回值不是一個promise唠粥,那么其返回值將作為下一個then的onFulfilled參數(shù);如果onFulfilled的返回值是一個成功的promise停做,那么這個promise的成功結(jié)果將作為下一個then的onFulfilled參數(shù)晤愧;如果onFulfilled的返回值是一個失敗的promise,那么這個promise的失敗原因?qū)⒆鳛橄乱粋€then的onRejected參數(shù)雅宾。
onRejected(可選):將在promise的狀態(tài)變成rejected時調(diào)用养涮,參數(shù)為promise失敗的原因葵硕。其返回值的行為與onFulfilled的返回值一致。
promise.catch(onRejected)
onRejected在promise的狀態(tài)變成rejected時調(diào)用贯吓,參數(shù)為失敗原因懈凹。其返回值的行為與onFulfilled的返回值一致。
promise.finally(onFinally)
在 promise 結(jié)束時悄谐,無論結(jié)果是 fulfilled 或者是 rejected介评,都會執(zhí)行onFinally。這樣避免了同樣的語句在then和catch里各寫一次的情況爬舰。
Promise的靜態(tài)方法
Promise.all(iterable)
這個方法返回一個新的 promise 對象们陆,該 promise 對象在 iterable 參數(shù)對象里所有的 promise 對象都成功的時候才會觸發(fā)成功,一旦有任何一個 iterable 里面的 promise 對象失敗則立即觸發(fā)該 promise 對象的失敗情屹。這個新的 promise 對象在觸發(fā)成功狀態(tài)以后坪仇,會把一個包含 iterable 里所有 promise 返回值的數(shù)組作為成功回調(diào)的返回值,順序跟 iterable 的順序保持一致垃你;如果這個新的 promise 對象觸發(fā)了失敗狀態(tài)椅文,它會把 iterable 里第一個觸發(fā)失敗的 promise 對象的錯誤信息作為它的失敗錯誤信息。Promise.all 方法常被用于處理多個 promise 對象的狀態(tài)集合惜颇。
Promise.allSettled(iterable)
等到所有 promises 都已敲定(settled)(每個 promise 都已兌現(xiàn)(fulfilled)或已拒絕(rejected))皆刺。返回一個 promise,該 promise 在所有 promise 完成后完成凌摄。并帶有一個對象數(shù)組羡蛾,每個對象對應每個 promise 的結(jié)果。
Promise.any(iterable)
接收一個 Promise 對象的集合锨亏,當其中的一個 promise 成功痴怨,就返回那個成功的 promise 的值。
Promise.race(iterable)
當 iterable 參數(shù)里的任意一個子 promise 被成功或失敗后器予,父 promise 馬上也會用子 promise 的成功返回值或失敗詳情作為參數(shù)調(diào)用父 promise 綁定的相應句柄腿箩,并返回該 promise 對象。
Promise.resolve(value)
返回一個狀態(tài)由給定 value 決定的 Promise 對象劣摇。如果該值是 thenable(即,帶有 then 方法的對象)弓乙,返回的 Promise 對象的最終狀態(tài)由 then 方法執(zhí)行決定末融;否則的話(該 value 為空,基本類型或者不帶 then 方法的對象),返回的 Promise 對象狀態(tài)為 fulfilled暇韧,并且將該 value 傳遞給對應的 then 方法勾习。通常而言,如果您不知道一個值是否是 Promise 對象懈玻,使用 Promise.resolve(value) 來返回一個 Promise 對象,這樣就能將該 value 以 Promise 對象形式使用巧婶。
Promise.reject(reason)
返回一個狀態(tài)為失敗的 Promise 對象,并將給定的失敗信息傳遞給對應的處理方法。
Promise的實現(xiàn)
實現(xiàn)構(gòu)造函數(shù)
首先艺栈,Promise構(gòu)造函數(shù)的參數(shù)是一個具有兩個函數(shù)作為參數(shù)的函數(shù)英岭,Promise的初始狀態(tài)為pending
class Promise {
constructor(executor) {
//一個promise的狀態(tài)只能是pending,fulfilled或者rejected之一
//初始狀態(tài)為pending,且狀態(tài)只能由pending變成fulfilled或者rejected
this.state = 'pending';
//保存promise成功時的值
this.value = null;
//保存promise失敗時的值
this.reason = null;
//調(diào)用resolve代表成功
let resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';//成功時狀態(tài)變更為fulfilled
this.value = value;
}
};
//調(diào)用reject代表失敗
let reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';//失敗時狀態(tài)變更為rejected
this.reason = reason;
}
};
//實例化一個promise時,構(gòu)造函數(shù)的參數(shù)會立即執(zhí)行,且這個參數(shù)是一個帶有兩個參數(shù)的函數(shù)
//構(gòu)造函數(shù)內(nèi)部出錯時狀態(tài)變更為rejected
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
}
實現(xiàn)then的基礎(chǔ)(還未涉及微任務和鏈式調(diào)用)
onFulfilledArr和onRejectedArr分別保存then中注冊的onFulfilled和onRejected,在Promise狀態(tài)改變時執(zhí)行其保存的函數(shù)湿右。這里使用的發(fā)布/訂閱模式诅妹,onFulfilled和onRejected相當于訂閱者,resolve和reject相當于發(fā)布者毅人。
class Promise {
constructor(executor) {
//一個promise的狀態(tài)只能是pending,fulfilled或者rejected之一
//初始狀態(tài)為pending,且狀態(tài)只能由pending變成fulfilled或者rejected
this.state = 'pending';
//保存promise成功時的值
this.value = null;
//保存promise失敗時的值
this.reason = null;
//保存成功的回調(diào)函數(shù),用數(shù)組保存(一個promise實例可能有多個then)
this.onFulfilledArr = [];
//保存失敗的回調(diào)函數(shù)
this.onRejectedArr = [];
//調(diào)用resolve代表成功
let resolve = (value) => {
//狀態(tài)只能由pending變成fulfilled或者rejected
if (this.state === 'pending') {
this.state = 'fulfilled';//成功時狀態(tài)變更為fulfilled
this.value = value;
//執(zhí)行then中注冊的成功回調(diào)
this.onFulfilledArr.forEach(func => {
func();
});
}
};
//調(diào)用reject代表失敗
let reject = (reason) => {
//狀態(tài)只能由pending變成fulfilled或者rejected
if (this.state === 'pending') {
this.state = 'rejected';//失敗時狀態(tài)變更為rejected
this.reason = reason;
//執(zhí)行then中注冊的失敗回調(diào)
this.onRejectedArr.forEach(func => {
func();
});
}
};
//實例化一個promise時,構(gòu)造函數(shù)的參數(shù)會立即執(zhí)行,且這個參數(shù)是一個帶有兩個參數(shù)的函數(shù)
//構(gòu)造函數(shù)內(nèi)部出錯時狀態(tài)變更為rejected
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
//then方法,onFulfilled和onRejected分別表示成功和失敗回調(diào)
then(onFulfilled, onRejected) {
//還在等待
if (this.state === 'pending') {
//需要保存回調(diào)方法,在狀態(tài)改變后再執(zhí)行
this.onFulfilledArr.push(() => {
if (typeof onFulfilled === 'function') {
onFulfilled(this.value);//將resolve的參數(shù)傳給onFulfilled
}
})
this.onRejectedArr.push(() => {
if (typeof onRejected === 'function') {
onRejected(this.reason);//將resolve的參數(shù)傳給onFulfilled
}
})
} else {
//狀態(tài)已經(jīng)改變了
//成功
if (this.state === 'fulfilled') {
if (typeof onFulfilled === 'function') {
onFulfilled(this.value);
}
}
//失敗
if (this.state === 'rejected') {
if (typeof onRejected === 'function') {
onRejected(this.reason);
}
}
}
}
}
實現(xiàn)鏈式調(diào)用
鏈式調(diào)用的關(guān)鍵在于then方法的返回值也是一個Promise實例吭狡,個人認為Promise的核心就是then方法,將then理解透徹了丈莺,其他的實例和靜態(tài)方法就很好
class Promise {
constructor(executor) {
//一個promise的狀態(tài)只能是pending,fulfilled或者rejected之一
//初始狀態(tài)為pending,且狀態(tài)只能由pending變成fulfilled或者rejected
this.state = 'pending';
//保存promise成功時的值
this.value = null;
//保存promise失敗時的值
this.reason = null;
//保存成功的回調(diào)函數(shù),用數(shù)組保存(一個promise實例可能有多個then)
this.onFulfilledArr = [];
//保存失敗的回調(diào)函數(shù)
this.onRejectedArr = [];
//調(diào)用resolve代表成功
let resolve = (value) => {
//狀態(tài)只能由pending變成fulfilled或者rejected
if (this.state === 'pending') {
this.state = 'fulfilled';//成功時狀態(tài)變更為fulfilled
this.value = value;
//執(zhí)行then中注冊的成功回調(diào)
this.onFulfilledArr.forEach(func => {
func();
})
}
};
//調(diào)用reject代表失敗
let reject = (reason) => {
//狀態(tài)只能由pending變成fulfilled或者rejected
if (this.state === 'pending') {
this.state = 'rejected';//失敗時狀態(tài)變更為rejected
this.reason = reason;
//執(zhí)行then中注冊的失敗回調(diào)
this.onRejectedArr.forEach(func => {
func();
})
}
};
//實例化一個promise時,構(gòu)造函數(shù)的參數(shù)會立即執(zhí)行,且這個參數(shù)是一個帶有兩個參數(shù)的函數(shù)
//構(gòu)造函數(shù)內(nèi)部出錯時狀態(tài)變更為rejected
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
//then方法,onFulfilled和onRejected分別表示成功和失敗回調(diào)
//then是Promise實例的方法,then可以調(diào)用then,說明then的返回值也是一個Promise實例
then(onFulfilled, onRejected) {
//then內(nèi)部返回的promise
let promise = new Promise((resolve, reject) => {
//還在等待(異步)
if (this.state === 'pending') {
//需要保存回調(diào)方法,在狀態(tài)改變后再執(zhí)行
this.onFulfilledArr.push(() => {
//這使用異步是為了能夠拿到promise實例,在構(gòu)造函數(shù)中直接拿會報錯,queueMicrotask在node環(huán)境中可以使用process.nextTick代替
queueMicrotask(() => {
try {
if (typeof onFulfilled === 'function') {
let x = onFulfilled(this.value);
//成功回調(diào)有返回值時才傳給下一個then
resolvePromise(promise, x, resolve, reject);
} else {
resolve(this.value);//如果沒有寫成功回調(diào),那么將成功的回調(diào)的參數(shù)傳給下一個then的成功回調(diào)
}
} catch (e) {
reject(e);
}
})
//try catch無法捕獲異步中的錯誤,因此不這樣寫
// try {
// if (typeof onFulfilled === 'function') {
// let x = onFulfilled(this.value);
// //成功回調(diào)有返回值時才傳給下一個then
// queueMicrotask(()=>{
// resolvePromise(promise, x, resolve, reject);
// })
// } else {
// resolve(this.value);//如果沒有寫成功回調(diào),那么將成功的回調(diào)的參數(shù)傳給下一個then的成功回調(diào)
// }
// } catch (e) {
// reject(e);
// }
})
this.onRejectedArr.push(() => {
queueMicrotask(() => {
try {
if (typeof onRejected === 'function') {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} else {
reject(this.reason);//如果沒有寫失敗回調(diào),那么將失敗的回調(diào)的參數(shù)傳給下一個then的失敗回調(diào)
}
} catch (e) {
reject(e);
}
})
})
} else {
//狀態(tài)已經(jīng)改變了
//成功
if (this.state === 'fulfilled') {
queueMicrotask(() => {
try {
if (typeof onFulfilled === 'function') {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} else {
resolve(this.value);
}
} catch (e) {
reject(e);
}
})
}
//失敗
if (this.state === 'rejected') {
queueMicrotask(() => {
try {
if (typeof onRejected === 'function') {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} else {
reject(this.reason);
}
} catch (e) {
reject(e);
}
})
}
}
})
return promise;
}
}
//then內(nèi)部的promise是如何將返回值傳遞給下一個then的
let resolvePromise = function (promise, x, resolve, reject) {
if (x === promise) {//防止出現(xiàn)自己等待自己的情況
//這種情況下就會報錯
// let promise=new Promise((resolve,reject)=>{
// resolve('aa');
// })
// let a=promise.then(res=>{
// return a;
// })
let err = new TypeError('Chaining cycle detected for promise #<Promise>');
console.error(err);
} else {
if (x instanceof Promise) {
//當x是一個Promise實例時划煮,將then內(nèi)部返回的promise的resolve和reject注冊為x的成功和失敗回調(diào)
//當x的狀態(tài)改變時,x調(diào)用自己的resolve和reject也就是調(diào)用了then內(nèi)部的resolve和reject
x.then(resolve, reject);
} else {
//x只是一個普通對象時直接傳給下一個then的成功回調(diào)作為參數(shù)
//then中失敗回調(diào)的返回值也會傳給下一個then的成功回調(diào)作為參數(shù)
resolve(x);
}
}
}
Promise實例的catch和finally方法
catch其實就是只有失敗回調(diào)的then方法缔俄,finally的返回值也是一個Promise實例
// catch 是一個只有失敗回調(diào)的then函數(shù)
catch(onRejected) {
return this.then(null, onRejected);
}
//finally()方法返回一個Promise弛秋。在promise結(jié)束時,無論結(jié)果是fulfilled或者是rejected,都會執(zhí)行指定的回調(diào)函數(shù)。這為在Promise是否成功完成后都需要執(zhí)行的代碼提供了一種方式牵现。
//這避免了同樣的語句需要在then()和catch()中各寫一次的情況铐懊。
finally(onFinally) {
return new Promise((resolve, reject) => {
this.then(res => {
try {
onFinally && onFinally();
resolve(res);//將結(jié)果傳給finally的then
} catch (e) {
reject(e);
}
}, err => {
try {
onFinally && onFinally();
reject(err);
} catch (e) {
reject(e);
}
})
})
}
Promise的靜態(tài)方法
Promise靜態(tài)方法的作用在簡介里,代碼注釋中也有瞎疼,這里不再簡述科乎,直接上Promise的完整代碼
class Promise {
constructor(executor) {
//一個promise的狀態(tài)只能是pending,fulfilled或者rejected之一
//初始狀態(tài)為pending,且狀態(tài)只能由pending變成fulfilled或者rejected
this.state = 'pending';
//保存promise成功時的值
this.value = null;
//保存promise失敗時的值
this.reason = null;
//保存成功的回調(diào)函數(shù),用數(shù)組保存(一個promise實例可能有多個then)
this.onFulfilledArr = [];
//保存失敗的回調(diào)函數(shù)
this.onRejectedArr = [];
//調(diào)用resolve代表成功
let resolve = (value) => {
//狀態(tài)只能由pending變成fulfilled或者rejected
if (this.state === 'pending') {
this.state = 'fulfilled';//成功時狀態(tài)變更為fulfilled
this.value = value;
//執(zhí)行then中注冊的成功回調(diào)
this.onFulfilledArr.forEach(func => {
func();
})
}
};
//調(diào)用reject代表失敗
let reject = (reason) => {
//狀態(tài)只能由pending變成fulfilled或者rejected
if (this.state === 'pending') {
this.state = 'rejected';//失敗時狀態(tài)變更為rejected
this.reason = reason;
//執(zhí)行then中注冊的失敗回調(diào)
this.onRejectedArr.forEach(func => {
func();
})
}
};
//實例化一個promise時,構(gòu)造函數(shù)的參數(shù)會立即執(zhí)行,且這個參數(shù)是一個帶有兩個參數(shù)的函數(shù)
//構(gòu)造函數(shù)內(nèi)部出錯時狀態(tài)變更為rejected
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
//then方法,onFulfilled和onRejected分別表示成功和失敗回調(diào)
//then是Promise實例的方法,then可以調(diào)用then,說明then的返回值也是一個Promise實例
then(onFulfilled, onRejected) {
//then內(nèi)部返回的promise
let promise = new Promise((resolve, reject) => {
//還在等待(異步)
if (this.state === 'pending') {
//需要保存回調(diào)方法,在狀態(tài)改變后再執(zhí)行
this.onFulfilledArr.push(() => {
//這使用異步是為了能夠拿到promise實例,在構(gòu)造函數(shù)中直接拿會報錯,queueMicrotask在node環(huán)境中可以使用process.nextTick代替
queueMicrotask(() => {
try {
if (typeof onFulfilled === 'function') {
let x = onFulfilled(this.value);
//成功回調(diào)有返回值時才傳給下一個then
resolvePromise(promise, x, resolve, reject);
} else {
resolve(this.value);//如果沒有寫成功回調(diào),那么將成功的回調(diào)的參數(shù)傳給下一個then的成功回調(diào)
}
} catch (e) {
reject(e);
}
})
//try catch無法捕獲異步中的錯誤,因此不這樣寫
// try {
// if (typeof onFulfilled === 'function') {
// let x = onFulfilled(this.value);
// //成功回調(diào)有返回值時才傳給下一個then
// queueMicrotask(()=>{
// resolvePromise(promise, x, resolve, reject);
// })
// } else {
// resolve(this.value);//如果沒有寫成功回調(diào),那么將成功的回調(diào)的參數(shù)傳給下一個then的成功回調(diào)
// }
// } catch (e) {
// reject(e);
// }
})
this.onRejectedArr.push(() => {
queueMicrotask(() => {
try {
if (typeof onRejected === 'function') {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} else {
reject(this.reason);//如果沒有寫失敗回調(diào),那么將失敗的回調(diào)的參數(shù)傳給下一個then的失敗回調(diào)
}
} catch (e) {
reject(e);
}
})
})
} else {
//狀態(tài)已經(jīng)改變了
//成功
if (this.state === 'fulfilled') {
queueMicrotask(() => {
try {
if (typeof onFulfilled === 'function') {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} else {
resolve(this.value);
}
} catch (e) {
reject(e);
}
})
}
//失敗
if (this.state === 'rejected') {
queueMicrotask(() => {
try {
if (typeof onRejected === 'function') {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} else {
reject(this.reason);
}
} catch (e) {
reject(e);
}
})
}
}
})
return promise;
}
// catch 是一個只有失敗回調(diào)的then函數(shù)
catch(onRejected) {
return this.then(null, onRejected);
}
//finally()方法返回一個Promise。在promise結(jié)束時,無論結(jié)果是fulfilled或者是rejected,都會執(zhí)行指定的回調(diào)函數(shù)贼急。這為在Promise是否成功完成后都需要執(zhí)行的代碼提供了一種方式茅茂。
//這避免了同樣的語句需要在then()和catch()中各寫一次的情況。
finally(onFinally) {
return new Promise((resolve, reject) => {
this.then(res => {
try {
onFinally && onFinally();
resolve(res);//將結(jié)果傳給finally的then
} catch (e) {
reject(e);
}
}, err => {
try {
onFinally && onFinally();
reject(err);
} catch (e) {
reject(e);
}
})
})
}
//靜態(tài)方法resolve
//返回一個狀態(tài)由給定value決定的Promise對象太抓。
//如果該值是thenable(即,帶有then方法的對象)空闲,返回的Promise對象的最終狀態(tài)由then方法執(zhí)行決定;
//否則的話(該value為空,基本類型或者不帶then方法的對象),返回的Promise對象狀態(tài)為fulfilled,并且將該value傳遞給對應的then方法。
//通常而言,如果您不知道一個值是否是Promise對象,使用Promise.resolve(value) 來返回一個Promise對象,這樣就能將該value以Promise對象形式使用走敌。
static resolve(res) {
return new Promise((resolve, reject) => {
if (res && res instanceof Promise) {//如果參數(shù)是Promise,那么最終的狀態(tài)由這個Promise決定
res.then(data => {
resolve(data);
}, err => {
reject(err);
})
} else {
resolve(res);//如果是普通對象,直接作為成功結(jié)果
}
})
}
//靜態(tài)方法reject
//Promise.reject()方法的參數(shù),會原封不動地作為reject的理由,變成后續(xù)方法的參數(shù)碴倾。這一點與Promise.resolve方法不一致。
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
//靜態(tài)方法race
//當iterable參數(shù)里的任意一個子promise被成功或失敗后,父promise馬上也會用子promise的成功返回值或失敗詳情作為參數(shù)調(diào)用父promise綁定的相應句柄,并返回該promise對象掉丽。
static race(promises) {
return new Promise((resolve, reject) => {//返回的promise
if (!isIterable(promises)) {//promises不是可迭代的對象直接失敗
let err = new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
reject(err);
throw err;
}
for (const promise of promises) {//利用Promise狀態(tài)凝固的特性,返回的promise的狀態(tài)只會改變一次跌榔。
// 當數(shù)組中的任意一個promise完成時,就會改變返回promise的狀態(tài),即使之后數(shù)組中其他promise也完成時,返回的promise也不再執(zhí)行resolve或reject
promise.then(res => {
resolve(res);
}, err => {
reject(err);
})
}
})
}
//靜態(tài)方法all
//這個方法返回一個新的promise對象,該promise對象在iterable參數(shù)對象里所有的promise對象都成功的時候才會觸發(fā)成功,
//一旦有任何一個iterable里面的promise對象失敗則立即觸發(fā)該promise對象的失敗捶障。
//這個新的promise對象在觸發(fā)成功狀態(tài)以后,會把一個包含iterable里所有promise返回值的數(shù)組作為成功回調(diào)的返回值,順序跟iterable的順序保持一致僧须;
//如果這個新的promise對象觸發(fā)了失敗狀態(tài),它會把iterable里第一個觸發(fā)失敗的promise對象的錯誤信息作為它的失敗錯誤信息。Promise.all方法常被用于處理多個promise對象的狀態(tài)集合项炼。
static all(promises) {
let resultArr = [];//保存promises的結(jié)果
let count = 0;//已完成的promise數(shù)量
return new Promise((resolve, reject) => {
if (!isIterable(promises)) {
let err = new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
reject(err);
throw err;
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
count++;
resultArr[i] = res;//按promises傳入順序保存
if (count === promises.length) {//promise已經(jīng)全部執(zhí)行完畢了
resolve(resultArr);
}
}, err => {
//立即觸發(fā)失敗,利用promise的狀態(tài)凝固,只會拋出第一個錯誤
reject(err);
})
}
})
}
//靜態(tài)方法allSettled
//等到所有promises都已敲定(settled)(每個promise都已兌現(xiàn)(fulfilled)或已拒絕(rejected))担平。
//返回一個promise,該promise在所有promise完成后完成示绊。并帶有一個對象數(shù)組,每個對象對應每個promise的結(jié)果。
static allSettled(promises) {
let resultArr = [];//保存promises的結(jié)果
let count = 0;//已完成的promise數(shù)量
return new Promise((resolve, reject) => {
if (!isIterable(promises)) {
let err = new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
reject(err);
throw err;
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(res => {
count++;
resultArr[i] = {
status: "fulfilled",
value: res,
};//按promises傳入順序保存
if (count === promises.length) {
resolve(resultArr);
}
}, err => {
count++;
resultArr[i] = {
status: "rejected",
value: err,
};
if (count === promises.length) {
resolve(resultArr);
}
})
}
})
}
//靜態(tài)方法any
//接收一個Promise對象的集合,當其中的一個promise成功,就返回那個成功的promise的值暂论。
static any(promises) {
let hasResolve = false;//是否有已經(jīng)成功的promise
return new Promise((resolve, reject) => {//返回的promise
if (!isIterable(promises)) {
let err = new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
reject(err);
throw err;
}
for (const promise of promises) {//利用Promise狀態(tài)凝固的特性,返回的promise的狀態(tài)只會改變一次面褐。
// 當數(shù)組中的任意一個promise完成時,就會改變返回promise的狀態(tài),即使之后數(shù)組中其他promise也完成時,返回的promise也不再執(zhí)行resolve或reject
promise.then(res => {
hasResolve = true;
resolve(res);
})
}
Promise.allSettled(promises).then(res => {
//所有promise狀態(tài)都敲定為失敗時
if (!hasResolve) {
reject('AggregateError: All promises were rejected');
}
})
})
}
}
//then內(nèi)部的promise是如何將返回值傳遞給下一個then的
let resolvePromise = function (promise, x, resolve, reject) {
if (x === promise) {//防止出現(xiàn)自己等待自己的情況
//這種情況下就會報錯
// let promise=new Promise((resolve,reject)=>{
// resolve('aa');
// })
// let a=promise.then(res=>{
// return a;
// })
let err = new TypeError('Chaining cycle detected for promise #<Promise>');
console.error(err);
} else {
if (x instanceof Promise) {
//當x是一個Promise實例時,將then內(nèi)部返回的promise的resolve和reject注冊為x的成功和失敗回調(diào)
//當x的狀態(tài)改變時空另,x調(diào)用自己的resolve和reject也就是調(diào)用了then內(nèi)部的resolve和reject
x.then(resolve, reject);
} else {
//x只是一個普通對象時直接傳給下一個then的成功回調(diào)作為參數(shù)
//then中失敗回調(diào)的返回值也會傳給下一個then的成功回調(diào)作為參數(shù)
resolve(x);
}
}
}
//判斷一個對象是否是可迭代的
let isIterable = function (obj) {
return obj != null && typeof obj[Symbol.iterator] === 'function';
}
ES5版本的實現(xiàn)
為了兼容IE9及以上版本盆耽,這里的代碼里的微任務queueMicrotask使用宏任務setTimeout代替
function Promise(executor) {
this.state = 'pending';
this.value = null;
this.reason = null;
this.onFulfilledArr = [];
this.onRejectedArr = [];
var self = this;
var resolve = function (res) {
if (self.state === 'pending') {
self.state = 'fulfilled';
self.value = res;
for (var i = 0; i < self.onFulfilledArr.length; i++) {
self.onFulfilledArr[i]();
}
}
}
//reject方法
var reject = function (reason) {
if (self.state === 'pending') {
self.state = 'rejected';
self.reason = reason;
for (var i = 0; i < self.onRejectedArr.length; i++) {
self.onRejectedArr[i]();
}
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
var self = this;
var promise = new Promise(function (resolve, reject) {
if (self.state === 'pending') {
//成功回調(diào)處理
self.onFulfilledArr.push(function () {
setTimeout(function () {
try {
if (typeof onFulfilled === 'function') {
var x = onFulfilled(self.value);
dealThen(promise, x, resolve, reject);
} else {
resolve(self.value);
}
} catch (e) {
reject(e);
}
})
})
self.onRejectedArr.push(function () {
setTimeout(function () {
try {
if (typeof onRejected === 'function') {
var x = onRejected(self.reason);
dealThen(promise, x, resolve, reject);
} else {
reject(self.reason);
}
} catch (e) {
reject(e);
}
})
})
}
if (self.state === 'fulfilled') {
setTimeout(function () {
try {
if (typeof onFulfilled === 'function') {
var x = onFulfilled(self.value);
dealThen(promise, x, resolve, reject);
} else {
resolve(self.value);
}
} catch (e) {
reject(e);
}
})
}
if (self.state === 'rejected') {
setTimeout(function () {
try {
if (typeof onRejected === 'function') {
var x = onRejected(self.reason);
dealThen(promise, x, resolve, reject);
} else {
reject(self.reason);
}
} catch (e) {
reject(e);
}
})
}
})
return promise;
}
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
Promise.prototype.finally = function (callback) {
var self = this;
return new Promise(function (resolve, reject) {
self.then(function (res) {
try {
callback();
resolve(res)
} catch (e) {
reject(e);
}
}, function (err) {
try {
callback();
reject(err)
} catch (e) {
reject(e);
}
})
})
}
Promise.resolve = function (res) {
return new Promise(function (resolve, reject) {
if (res && res.__proto__.constructor === Promise) {
res.then(function (data) {
resolve(data);
}, function (err) {
reject(err);
})
} else {
resolve(res);
}
})
}
Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason);
})
}
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
if (promises.__proto__.constructor !== Array) {
var err = new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
reject(err);
throw err;
}
for (var i = 0; i < promises.length; i++) {
promises[i].then(function (res) {
resolve(res);
}, function (err) {
reject(err);
})
}
})
}
Promise.all = function (promises) {
var resultArr = [];
var count = 0;
return new Promise(function (resolve, reject) {
if (promises.__proto__.constructor !== Array) {
var err = new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
reject(err);
throw err;
}
for (var i = 0; i < promises.length; i++) {
(function (i) {
promises[i].then(function (res) {
count++;
resultArr[i] = res;
if (count === promises.length) {
resolve(resultArr);
}
}, function (err) {
reject(err);
})
})(i)
}
})
}
Promise.allSettled = function (promises) {
var resultArr = [];
var count = 0;
return new Promise(function (resolve, reject) {
if (promises.__proto__.constructor !== Array) {
var err = new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
reject(err);
throw err;
}
for (var i = 0; i < promises.length; i++) {
(function (i) {
promises[i].then(function (res) {
count++;
resultArr[i] = {
status: "fulfilled",
value: res,
};
if (count === promises.length) {
resolve(resultArr);
}
}, function (err) {
count++;
resultArr[i] = {
status: "rejected",
value: err,
};
if (count === promises.length) {
resolve(resultArr);
}
})
})(i)
}
})
}
Promise.any = function (promises) {
var hasResolve = false;
return new Promise(function (resolve, reject) {
if (promises.__proto__.constructor !== Array) {
var err = new TypeError('object is not iterable (cannot read property Symbol(Symbol.iterator))');
reject(err);
throw err;
}
for (var i = 0; i < promises.length; i++) {
promises[i].then(function (res) {
resolve(res);
})
}
Promise.allSettled(promises).then(function (res) {
if (!hasResolve) {
reject('AggregateError: All promises were rejected');
}
})
})
}
function dealThen(promise, x, resolve, reject) {
if (x === promise) {
var err = new TypeError('Chaining cycle detected for promise #<Promise>');
console.error(err);
}
if (x) {
if (x.__proto__.constructor === Promise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
}