完整的Promise實現(xiàn)

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)用嗽测。

promises.png

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);
        }
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扼菠,隨后出現(xiàn)的幾起案子摄杂,更是在濱河造成了極大的恐慌,老刑警劉巖循榆,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件析恢,死亡現(xiàn)場離奇詭異,居然都是意外死亡秧饮,警方通過查閱死者的電腦和手機映挂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盗尸,“玉大人柑船,你說我怎么就攤上這事∑酶鳎” “怎么了鞍时?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長扣蜻。 經(jīng)常有香客問我逆巍,道長,這世上最難降的妖魔是什么莽使? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任锐极,我火速辦了婚禮,結(jié)果婚禮上芳肌,老公的妹妹穿的比我還像新娘灵再。我一直安慰自己,他們只是感情好亿笤,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布檬嘀。 她就那樣靜靜地躺著,像睡著了一般责嚷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掂铐,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天罕拂,我揣著相機與錄音揍异,去河邊找鬼。 笑死爆班,一個胖子當著我的面吹牛衷掷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播柿菩,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼戚嗅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了枢舶?” 一聲冷哼從身側(cè)響起懦胞,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凉泄,沒想到半個月后躏尉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡后众,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年胀糜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒂誉。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡教藻,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出右锨,到底是詐尸還是另有隱情括堤,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布陡蝇,位于F島的核電站痊臭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏登夫。R本人自食惡果不足惜广匙,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望恼策。 院中可真熱鬧鸦致,春花似錦、人聲如沸涣楷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狮斗。三九已至绽乔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碳褒,已是汗流浹背折砸。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工看疗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人睦授。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓两芳,卻偏偏與公主長得像,于是被迫代替她去往敵國和親去枷。 傳聞我的和親對象是個殘疾皇子怖辆,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內(nèi)容