1. 程式人生 > >前端面試?這份手擼Promise請你收下

前端面試?這份手擼Promise請你收下

前言

  現在很多大廠面試前端都會要求能夠手動的寫出一個Promise,所以這裡整理了一份手寫的Promise

  絕對詳細,功能絕對強大。如果你不瞭解Promise的基本使用,那麼本篇文章可能不太適合你,如果你對Promise有過一些瞭解,那麼這篇文章絕對是你進階的好幫手。

  除開catch()以及finally()allSettled介面沒實現之外,其他的所有原生Promise支援的功能此手寫的Promise都支援。

  書寫Promise的難度其實就在於then()方法的鏈式呼叫以及值穿透傳遞,其他的其實都還好。

  讓這篇文章滾進你的收藏夾吧!

Promise狀態實現

  在原生Promise

中具有三種狀態,分別是

pending:未解決狀態

fulfilled:已解決狀態

rejected:解決失敗狀態

  所以第一步,要先實現這三種狀態。

  並且在原生Promise中具有value用於記錄resolve()reject()中的值用於傳遞給then()方法。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {
                this.status = MyPromise.PENDING;  // 初始為準備狀態
                this.value = null;  // 初始值
        }

}

Promise執行函式

  原生Promise的建構函式中會接收一個executor引數,該引數當是一個函式。

  用於同步的執行當前任務,當任務完成後應該具有resolve()方法以及reject()方法來通知then()方法當前執行任務的執行狀態並傳遞值。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {
                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                executor(this.resolve, this.reject);  // 傳遞形參,執行executor函式
        }

        resolve(value) {

                this.status = MyPromise.FUFILLED;
                this.value = value;
        }

        reject(reason) {

                this.status = MyPromise.REJECTED;
                this.value = reason;

        }
}

  上面這樣寫在執行resolve()以及reject()時會出現問題,原因是this指向為undefiled(嚴格模式)。

<script src="./Promise核心.js"></script>
<script>

        "use strict";

        let p1 = new MyPromise((resolve, reject) => {
                resolve("成功")
        })

        console.log(p1);

</script>

  這是由於我們在執行函式中呼叫了resolve()reject(),故this指向為executor的函式上下文。

  解決這個問題可以使用bind()來改變this指向。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {
              
                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值
                executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
        }

        resolve(value) {
         
                this.status = MyPromise.FUFILLED;
                this.value = value;
        }

        reject(reason) {

                this.status = MyPromise.REJECTED;
                this.value = reason;

        }
}

Promise狀態限制

  當前Promise狀態只應該改變一次而不能多次改變,顯然我們上面的程式碼不能做到這點限制。

<script src="./Promise核心.js"></script>
<script>

        "use strict";

        let p1 = new MyPromise((resolve, reject) => {

                resolve("成功");
                reject("失敗");

                // 對於原生Promise來說,狀態只能改變一次。但是這裡卻允許兩次改變,故是有問題的
        })

        console.log(p1);  // MyPromise {status: "rejected", value: "失敗"}

</script>

  所以這裡要對程式碼加上限制。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值
                executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                }
        }
}

Promise執行異常

  在執行函式executor中可能引發異常,這會讓當前的Promise的狀態改變為rejected

  所以在上面程式碼基礎上需要加入try...catch進行處理。

  當then()方法捕捉到執行函式executor中的異常時,可以讓第二個引數的函式對其異常進行處理,但是我們目前還沒實現then(),所以直接丟給reject()即可,當實現then()時自然會使用到reject()中傳遞過來的值。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                }
        }
}

then方法基礎實現

  原生的Promise狀態改變後,可以執行其下的then()方法,所以我們需要來封裝出一個then()方法。

  then()方法接收兩個函式,第一個函式onFulfilled用於處理上一個Promisefulfilled狀態,第二個函式onRejected用於處理上一個Promiserejected狀態。

  並且then()方法中的這兩個函式都應該具有一個形參,用於接收到Promiseresolve()reject()中傳遞的值。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                }
        }

        then(onFulfilled, onRejected) {

                if(this.status == MyPromise.FUFILLED){  // 狀態改變時執行
                        onFulfilled(this.value);
                }

                if(this.status == MyPromise.REJECTED){  // 狀態改變時執行
                        onRejected(this.value);
                }
        }
}

then方法引數優化

  上面已經說過,then()方法具有兩個引數,這兩個引數分別對應兩個函式用來處理上一個Promsieresolve()reject()

  但是在原生Promise中,這兩個方法可以不進行傳遞,所以我們需要對上述程式碼進行優化。

  當then()方法中的某一個引數不為函式時,讓它自動建立一個空函式。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                }
        }

        then(onFulfilled, onRejected) {
                if(typeof onFulfilled != "function"){  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = ()=>{};
                }

                if(typeof onRejected != "function"){  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = ()=>{};
                }

                if(this.status == MyPromise.FUFILLED){  // 狀態改變時執行
                        onFulfilled(this.value);
                }

                if(this.status == MyPromise.REJECTED){  // 狀態改變時執行
                        onRejected(this.value);
                }
        }
}

then方法異常捕獲

  當then()方法中處理fulfilled狀態的函式onFulfilled或者處理rejected狀態的函式onRejected在執行時出現異常應該進行捕獲並且傳遞給下一個then()的處理rejected狀態的函式onRejected

  這裡我們先讓所有的異常都交由當前then()處理rejected狀態的函式onRejected,後面再進行優化。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                }
        }

        then(onFulfilled, onRejected) {
                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => { };
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => { };
                }

                if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                        try {  // then處理成功的函式onFulfilled中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                onFulfilled(this.value);
                        } catch (e) {
                                onRejected(e);
                        }

                }

                if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                        try {  // then處理失敗的函式onRejected中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                onRejected(this.value);
                        } catch (e) {
                                onRejected(e);
                        }
                }
        }
}

then方法非同步執行

  在原生的Promise中,executor函式是同步執行的,而then()方法是非同步執行故排在同步執行之後。

  但是我們的Promise卻沒有做到這一點,下面的實驗將說明這個問題

<script src="./Promise核心.js"></script>
<script>

        "use strict";

        let p1 = new MyPromise((resolve, reject) => {

                reject("失敗");

        }).then(
                null,
                error => {
                        console.log(error);  // 先列印  失敗
                }
        )

        console.log("hello,Promise");  // 後列印  hello,Promise

</script>

  最簡單的解決方案就是為then()中處理成功或處理失敗的函式執行外套上一個setTimeout,讓其處理排線上程同步任務執行之後再進行執行。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                }
        }

        then(onFulfilled, onRejected) {
                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => { };
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => { };
                }

                if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                        setTimeout(() =>  {  // 晚於執行緒同步任務執行
                                try {  // then處理成功的函式onFulfilled中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onFulfilled(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

                if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                        setTimeout(() =>  {  // 晚於執行緒同步任務執行
                                try {  // then處理失敗的函式onRejected中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onRejected(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }
        }
}

執行函式非同步阻塞

  此時我們的程式碼仍然具有一個問題,即在執行函式executor中使用setTimeout時,下面的then()會進行阻塞。

  這是因為當前Promise狀態是pendingthen()方法中並沒有對pending狀態進行處理的策略所導致的。

<script src="./Promise核心.js"></script>
<script>


        "use strict";

        new MyPromise((resolve, reject) => {
                setTimeout(() => {
                        resolve("成功");  // 同步任務執行完三秒後才會改變當前Promise狀態
                }, 3000);  

        }).then((success) => {  // 但是這裡先執行了then,Promise狀態為pending,故發生阻塞
                console.log(success);  // 阻塞了,不列印
        })

</script>

  既然當前Promise狀態是pending,3秒後狀態才發生改變,那麼我們就可以通過不斷的迴圈來看看它何時改變狀態。

  所以第一步是定義一個執行非同步的陣列。然後再將then()中處理正確的函式onFulfilled與處理錯誤的函式onRejected壓進去。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                this.callbacks = []; // 如果是一個非同步操作,則放入該陣列中

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }

             
        }

        resolve(value) {
             
                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;
                        })
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;
                }
        }

        then(onFulfilled, onRejected) {

                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => { };
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => { };
                }

                if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                        setTimeout(() =>  {  // 晚於執行緒同步任務執行
                                try {   // then處理成功的函式onFulfilled中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onFulfilled(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

                if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                        setTimeout(() =>  {  // 晚於執行緒同步任務執行
                                try {  // then處理失敗的函式onRejected中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onRejected(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

                if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。
                        this.callbacks.push({
                                onFulfilled,
                                onRejected,
                        });
                }
        }
}

  當陣列壓入完成後,執行函式executor會去呼叫resolve()或者reject()改變當前Promise狀態。

  所以我們還需要在resolve()reject()方法中對非同步的陣列處理函式進行呼叫。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                this.callbacks = []; // 如果是一個非同步操作,則放入該陣列中

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }

             
        }

        resolve(value) {
             
                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;

                        this.callbacks.map(callback => {  // // 呼叫處理非同步executor裡resolve的方法。
                                callback.onFulfilled(value);
                        })
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                        this.callbacks.map(callback => {  // 呼叫處理非同步executor裡reject的方法。
                                callback.onRejected(reason);
                        })

                }
        }

        then(onFulfilled, onRejected) {

                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => { };
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => { };
                }

                if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                        setTimeout(() =>  {  // 晚於執行緒同步任務執行
                                try {  // then處理成功的函式onFulfilled中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onFulfilled(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

                if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                        setTimeout(() =>  {  // 晚於執行緒同步任務執行
                                try {  // then處理失敗的函式onRejected中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onRejected(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

                if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。
                        this.callbacks.push({
                                onFulfilled,
                                onRejected,
                        });
                }
        }
}

非同步執行函式的then異常捕獲

  上面我們對同步執行函式executor呼叫then()方法中可能出現的異常進行了處理。

  就是下面這一段程式碼。

                if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                        setTimeout(() =>  {  // 晚於執行緒同步任務執行
                                try {  // then處理成功的函式onFulfilled中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onFulfilled(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

                if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                        setTimeout(() =>  {  // 晚於執行緒同步任務執行
                                try {  // then處理失敗的函式onRejected中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onRejected(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

  但是我們還沒有對非同步執行函式executor呼叫then()方法中可能出現的異常進行處理。

             if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。
                        this.callbacks.push({
                                onFulfilled,
                                onRejected,
                        });
                }
        }

  這會導致下面這樣的使用場景出現問題。

<script src="./Promise核心.js"></script>
<script>

        "use strict";

        new MyPromise((resolve, reject) => {
                setTimeout(() => {
                        resolve("成功");
                }, 3000);

        }).then((success) => {
                throw new Error("自定義異常丟擲");  // 直接在處理成功狀態的函式onFulfilled中丟擲了異常,顯然是不符合原生Promise的
        });

</script>

  那麼我們就來加上異常捕獲即可,這裡還是先傳遞給當前then()處理rejected狀態的函式,後面會做修改。

  因為原版Promise會傳遞給下一個then()中處理rejected狀態的函式,而不是當前then()

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                this.callbacks = []; // 如果是一個非同步操作,則放入該陣列中

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;

                        this.callbacks.map(callback => {  // // 呼叫處理非同步executor裡resolve的方法。
                                callback.onFulfilled(value);
                        })
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                        this.callbacks.map(callback => {  // 呼叫處理非同步executor裡reject的方法。
                                callback.onRejected(reason);
                        })

                }
        }

        then(onFulfilled, onRejected) {

                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => { };
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => { };
                }

                if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                        setTimeout(() => {  // 晚於執行緒同步任務執行
                                try {  // then處理成功的函式onFulfilled中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onFulfilled(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

                if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                        setTimeout(() => {  // 晚於執行緒同步任務執行
                                try {  // then處理失敗的函式onRejected中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                        onRejected(this.value);
                                } catch (e) {
                                        onRejected(e);
                                }
                        })
                }

                if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。

                        this.callbacks.push({
                                onFulfilled: value => {
                                        try {  //  非同步executor改變狀態對其then中的onFulfilled進行異常捕獲
                                                onFulfilled(value);
                                        } catch (e) {
                                                onRejected(e);
                                        }
                                },
                                onRejected: value => {
                                        try {  //  非同步executor改變狀態對其then中的onRejected進行異常捕獲
                                                onRejected(value);
                                        } catch (e) {
                                                onRejected(e);
                                        }
                                }
                        });
                }
        }
}

then方法鏈式操作

  對於原生的Promise來講,每一個then()最後返回的都是一個新的Promise。所以才能達到支援不斷的then()進行鏈式操作,所以我們也可以這樣做。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                this.callbacks = []; // 如果是一個非同步操作,則放入該陣列中

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;

                        this.callbacks.map(callback => {  // // 呼叫處理非同步executor裡resolve的方法。
                                callback.onFulfilled(value);
                        })
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                        this.callbacks.map(callback => {  // 呼叫處理非同步executor裡reject的方法。
                                callback.onRejected(reason);
                        })

                }
        }

        then(onFulfilled, onRejected) {

                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => { };
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => { };
                }

                return new MyPromise((resolve, reject) => { // 返回一個新的Promise

                        if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {  // then處理成功的函式onFulfilled中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                                onFulfilled(this.value);
                                        } catch (e) {
                                                onRejected(e);
                                        }
                                })
                        }

                        if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {  // then處理失敗的函式onRejected中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                                onRejected(this.value);
                                        } catch (e) {
                                                onRejected(e);
                                        }
                                })
                        }

                        if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。

                                this.callbacks.push({
                                        onFulfilled: value => {
                                                try {  //  非同步executor改變狀態對其then中的onFulfilled進行異常捕獲
                                                        onFulfilled(value);
                                                } catch (e) {
                                                        onRejected(e);
                                                }
                                        },
                                        onRejected: value => {
                                                try {  //  非同步executor改變狀態對其then中的onRejected進行異常捕獲
                                                        onRejected(value);
                                                } catch (e) {
                                                        onRejected(e);
                                                }
                                        }
                                });
                        }
                });


        }
}

  現在我們的Promise已經支援then()的鏈式操作了,但是上面程式碼還是遺留了幾個問題。

  1.then()還沒有返回值,返回普通值該怎麼處理,返回一個新的Promise該怎麼處理

  2.沒有異常傳遞,原生Promise中的then()當丟擲異常時應該進行捕獲並傳遞給下一個then()

  3.不支援then()穿透

  4.不支援型別限制

  接下來繼續對程式碼做出優化調整。

then中返回普通值

  在原生的Promise中每一個then()所產生的Promise預設狀態都是fulfilled,如果當前then()返回是一個值的話那麼下一個then()將接受到該值。

  這個也非常簡單,程式碼接收一下每一個onFulfilled()onRejected()的返回值就好,並使用resolve()改變狀態為fulfilled以及將值進行傳遞給下一個then()

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                this.callbacks = []; // 如果是一個非同步操作,則放入該陣列中

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;

                        this.callbacks.map(callback => {  // // 呼叫處理非同步executor裡resolve的方法。
                                callback.onFulfilled(value);
                        })
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                        this.callbacks.map(callback => {  // 呼叫處理非同步executor裡reject的方法。
                                callback.onRejected(reason);
                        })

                }
        }

        then(onFulfilled, onRejected) {

                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => { };
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => { };
                }

                return new MyPromise((resolve, reject) => { // 返回一個新的Promise

                        if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {  // then處理成功的函式onFulfilled中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                                let result = onFulfilled(this.value);
                                                resolve(result);
                                        } catch (e) {
                                                onRejected(e);
                                        }
                                })
                        }

                        if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {  // then處理失敗的函式onRejected中出現異常,交由當前then處理失敗的函式onRejected函式進行處理。這個後面會做優化
                                                let result = onRejected(this.value);
                                                resolve(result);
                                        } catch (e) {
                                                onRejected(e);
                                        }
                                })
                        }

                        if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。

                                this.callbacks.push({
                                        onFulfilled: value => {
                                                try {  //  非同步executor改變狀態對其then中的onFulfilled進行異常捕獲
                                                        let result = onFulfilled(value);
                                                        resolve(result);
                                                } catch (e) {
                                                        onRejected(e);
                                                }
                                        },
                                        onRejected: value => {
                                                try {  //  非同步executor改變狀態對其then中的onRejected進行異常捕獲
                                                        let result = onRejected(value);
                                                        resolve(result);
                                                } catch (e) {
                                                        onRejected(e);
                                                }
                                        }
                                });
                        }
                });


        }
}

  這樣我們的then()就支援返回普通值了。

<script src="./Promise核心.js"></script>
<script>

        "use strict";

        new MyPromise((resolve, reject) => {
                setTimeout(() => {
                        resolve("成功");
                }, 3000);
        }).then((success) => {
                return "hello";
        }).then((success)=>{ 
                console.log(success);  // hello
        });

</script>

then中的異常傳遞

  在上面的程式碼中,then()方法裡的處理成功函式onFulfilled以及處理失敗函式onRejected在程式碼執行時丟擲的異常都會統一進行捕獲並且傳遞給當前then()方法處理失敗的函式onRejected

  這個與原生的Promise有出入,對於原生Promise來講應該是傳遞給下一個then()進行處理而不是當前then()

  改動也非常簡單,將原來發生異常傳遞的函式onRejected()改為reject()即可,這就是傳遞給下一個then()

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                this.callbacks = []; // 如果是一個非同步操作,則放入該陣列中

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;

                        this.callbacks.map(callback => {  // // 呼叫處理非同步executor裡resolve的方法。
                                callback.onFulfilled(value);
                        })
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                        this.callbacks.map(callback => {  // 呼叫處理非同步executor裡reject的方法。
                                callback.onRejected(reason);
                        })

                }
        }

        then(onFulfilled, onRejected) {

                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => { };
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => { };
                }

                return new MyPromise((resolve, reject) => { // 返回一個新的Promise

                        if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try { 
                                                let result = onFulfilled(this.value);
                                                resolve(result);
                                        } catch (e) {
                                                reject(e); // 傳遞給下一個then
                                        }
                                })
                        }

                        if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {  
                                                let result = onRejected(this.value);
                                                resolve(result);
                                        } catch (e) {
                                                reject(e); // 傳遞給下一個then
                                        }
                                })
                        }

                        if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。

                                this.callbacks.push({
                                        onFulfilled: value => {
                                                try {  
                                                        let result = onFulfilled(value);
                                                        resolve(result);
                                                } catch (e) {
                                                        reject(e); // 傳遞給下一個then
                                                }
                                        },
                                        onRejected: value => {
                                                try { 
                                                        let result = onRejected(value);
                                                        resolve(result);
                                                } catch (e) {
                                                        reject(e); // 傳遞給下一個then
                                                }
                                        }
                                });
                        }
                });


        }
}
<script src="./Promise核心.js"></script>
<script>

        "use strict";

        new MyPromise((resolve, reject) => {
                setTimeout(() => {
                        resolve("成功");
                }, 3000);
        }).then((success) => {
                throw new Error("新錯誤");
        }).then(null, error => {
                console.log(error);  // 上一個then的錯誤成功由該then接收
        });

</script>

then穿透功能實現

  在原生的Promise中是支援then()的穿透傳值的。

<script>

        "use strict";

        new Promise((resolve, reject) => {

                resolve("成功");

        })
                .then() // 穿透
                .then(
                        success => {
                                console.log(success); // 成功

                        },
                        error => {
                                console.log(error);
                        })

</script>

  但是我們的Promise卻不支援。

<script src="./Promise核心.js"></script>
<script>

        "use strict";

        new MyPromise((resolve, reject) => {

                resolve("成功");

        })
                .then() // 不支援穿透
                .then(
                        success => {
                                console.log(success); 

                        },
                        error => {
                                console.log(error);
                        })

</script>

  原因在於如果沒有對then()進行傳遞引數,那麼內部其實是會建立兩個空函式。

  我們只需要在空函式內部返回this.value即可。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                this.callbacks = []; // 如果是一個非同步操作,則放入該陣列中

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;

                        this.callbacks.map(callback => {  // // 呼叫處理非同步executor裡resolve的方法。
                                callback.onFulfilled(value);
                        })
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                        this.callbacks.map(callback => {  // 呼叫處理非同步executor裡reject的方法。
                                callback.onRejected(reason);
                        })

                }
        }

        then(onFulfilled, onRejected) {

                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => this.value;  // 支援穿透
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => this.value;  // 支援穿透
                }

                return new MyPromise((resolve, reject) => { // 返回一個新的Promise

                        if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {  
                                                let result = onFulfilled(this.value);
                                                resolve(result);
                                        } catch (e) {
                                                reject(e); // 傳遞給下一個then
                                        }
                                })
                        }

                        if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {  
                                                let result = onRejected(this.value);
                                                resolve(result);
                                        } catch (e) {
                                                reject(e); // 傳遞給下一個then
                                        }
                                })
                        }

                        if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。

                                this.callbacks.push({
                                        onFulfilled: value => {
                                                try {
                                                        let result = onFulfilled(value);
                                                        resolve(result);
                                                } catch (e) {
                                                        reject(e); // 傳遞給下一個then
                                                }
                                        },
                                        onRejected: value => {
                                                try {
                                                        let result = onRejected(value);
                                                        resolve(result);
                                                } catch (e) {
                                                        reject(e); // 傳遞給下一個then
                                                }
                                        }
                                });
                        }
                });


        }
}

then返回Promise

  原生的Promise支援返回一個新的Promise,但是我們的Promise現在還不支援。

  其實也很簡單,判斷一下then()中兩個函式返回的是不是一個新的Promise,如果是的話則使用其then()方法將其中resolve()reject()的值進行傳遞。

class MyPromise {

        static PENDING = "pending";
        static FUFILLED = "fulfilled";
        static REJECTED = "rejected";

        constructor(executor) {

                this.status = MyPromise.PENDING;  // 初始狀態為準備狀態
                this.value = null;  // 初始值

                this.callbacks = []; // 如果是一個非同步操作,則放入該陣列中

                try {
                        executor(this.resolve.bind(this), this.reject.bind(this));  // 傳遞形參,執行executor函式
                } catch (e) {
                        this.status = MyPromise.REJECTED; // 異常發生改變狀態
                        this.reject(e); // 記錄異常資訊
                }


        }

        resolve(value) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.FUFILLED;
                        this.value = value;

                        this.callbacks.map(callback => {  // // 呼叫處理非同步executor裡resolve的方法。
                                callback.onFulfilled(value);
                        })
                }
        }

        reject(reason) {

                if (this.status == MyPromise.PENDING) {  // 限制
                        this.status = MyPromise.REJECTED;
                        this.value = reason;

                        this.callbacks.map(callback => {  // 呼叫處理非同步executor裡reject的方法。
                                callback.onRejected(reason);
                        })

                }
        }

        then(onFulfilled, onRejected) {

                if (typeof onFulfilled != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onFulfilled = () => this.value;  // 支援穿透
                }

                if (typeof onRejected != "function") {  // 如果傳入的不是一個函式,預設建立空函式
                        onRejected = () => this.value;  // 支援穿透
                }

                return new MyPromise((resolve, reject) => { // 返回一個新的Promise

                        if (this.status == MyPromise.FUFILLED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {
                                                let result = onFulfilled(this.value);
                                                if (result instanceof MyPromise) {  // 判斷是否返回Promise物件
                                                        result.then(resolve, reject);
                                                } else {
                                                        resolve(result); // 改變狀態並將值交由下一個then接收
                                                }
                                        } catch (e) {
                                                reject(e); // 傳遞給下一個then
                                        }
                                })
                        }

                        if (this.status == MyPromise.REJECTED) {   // 狀態改變時執行

                                setTimeout(() => {  // 晚於執行緒同步任務執行
                                        try {
                                                let result = onRejected(this.value);
                                                if (result instanceof MyPromise) {  // 判斷是否返回Promise物件
                                                        result.then(resolve, reject);
                                                } else {
                                                        resolve(result); // 改變狀態並將值交由下一個then接收
                                                }
                                        } catch (e) {
                                                reject(e); // 傳遞給下一個then
                                        }
                                })
                        }

                        if (this.status == MyPromise.PENDING) {  // 如果當前Promise是等待處理狀態,則將處理成功的函式與處理失敗的函式壓入非同步陣列。

                                this.callbacks.push({
                                        onFulfilled: value => {
                                                try {
                                                        let result = onFulfilled(value);
                                                        if (result instanceof MyPromise) {  // 判斷是否返回Promise物件
                                                                result.then(resolve, reject);
                                                        } else {
                                                                resolve(result); // 改變狀態並將值交由下一個then接收
                                                        }
                                                } catch (e) {
                                                        reject(e); // 傳遞給下一個then
                                                }
                                        },
                                        onRejected: value => {
                                                try {
                                                        let result = onRejected(value);
                                                        if (result instanceof MyPromise) {  // 判斷是否返回Promise物件
                                                                result.then(resolve, reject);