天天看點

Promise源碼解密-then的鍊式調用

系列文章

  1. Promise源碼解密-PromisesA+标準
  2. Promise源碼解密-同步版
  3. Promise源碼解密-異步版
  4. Promise源碼解密-then的鍊式調用
  5. Promise源碼解密-catch/resolve/reject/race

創作不易 拒絕白嫖 點個贊呗

關注專欄

Promise源碼解密 ,帶你走進Promise的深處!!!

then的用法

  1. 通過return 給下一個then傳值,成功/失敗的傳回值,最後都是傳到下一個then的成功會回調
let t = new Promise((resolve, reject) => {
    console.log(a)  // 執行console會報錯,最終隻會執行reject
})
t.then((res)=>{
    return res
},error=>{
    return error
}).then(
  (res) => {
    console.log(res.toString(),'res===='); // ReferenceError: a is not defined res====
  },
  (error) => {
    console.log(error);
  }
);      
  1. then中的onFulfilled/onReject 是可選的, 下面的例子,第一個then沒有return值,但是第二個then也可以接受到值,最終輸出 then 回調可選。
let t = new Promise((resolve, reject) => {
    resolve('then 回調可選')
})
t.then().then(
  (res) => {
    console.log(res);
  },
  (error) => {
    console.log(error);
  }
);      
  1. 執行個體不可 循環引用,報錯 : Chaining cycle detected for promise #
let p = new Promise((resolve, reject) => {
    resolve('不可循環引用')
})
var p2=p.then(()=>{
   return p2 // 傳回的值還是p2
})      

完整代碼

// 定義狀态常量
const STATUS_PENDING = "pending";
const STATUS_FULFILLED = "fulfilled";
const STATUS_REJECTED = "rejected";

function resolvePromise(promise2, x, resolve, reject) {
    // 用來儲存是否已經reject或者resolve過
    let called
    if (promise2 === x) {
        throw new TypeError('Chaining cycle detected for promise')
    }
    // 如果是函數或者object的話先預設是promise
    if (x != null && (typeof x === 'object' || typeof x === 'function')) {
        try {
            let then = x.then
            // 如果then是函數的話
            if (typeof then === 'function') {
                // 為啥不直接x.then()
                // 因為then已經判斷過是不是function,但是x.then沒有判斷過
                // 就讓then執行 第一個參數是this   後面是成功的回調 和 失敗的回調

                //  這裡的y是啥,如果x是promsie的話,那麼y就是x中的resolve/reject的值
                then.call(x, y => {
                    // 成功和失敗隻能調用一個

                    if (called) return;
                    called = true;
                    console.log(y, 'yyyyyyyyyyyy')

                    // resolve的結果依舊是promise 那就繼續解析
                    resolvePromise(promise2, y, resolve, reject);
                }, err => {
                    // 成功和失敗隻能調用一個

                    if (called) return;
                    called = true;
                    reject(err);
                })
            } else {

                resolve(x); // 如果不是函數,那就直接傳回結果
            }
        } catch (error) {
            // 成功和失敗隻能調用一個

            if (called) return;
            called = true;
            // 沒有then 不是函數也不是普通值
            reject(error)
        }
    } else {
        // x 是一個普通值
        resolve(x)
    }
}
class MyPromise {
    // 接收一個 執行器
    // new Promise的時候,執行器立即執行,
    // 執行的時候根據指定函數執行
    // 并且程式報錯的情況下
    constructor(executor) {
        this.status = STATUS_PENDING;
        this.value = undefined;
        this.reason = undefined;

        // 這裡的兩個資料,相當于訂閱者的籃子,then相當于訂閱者,接收到釋出者的函數,儲存在籃子裡
        this.onFulfilledCallBacks = [];
        this.onRejectCallBacks = [];
        try {
            // 這裡将傳入的resolve和reject變為類中的調用的話。
            // (resolve, reject) => {
            //     resolve("then鍊式調用");=>this.resolve(then鍊式調用)
            // }

            executor(this.resolve, this.reject);
        } catch (error) {
            //  報錯的話直接将錯誤原因作為reason
            this.reject(error);
        }
    }
    // 這裡為啥使用箭頭函數而不是resolve(){}
    // 這是因為上面的executor調用的時候,resolve中的this其實是undefined
    // executor單獨調用了resolve/reject 這時,這兩個方法存在于執行是的環境,this不再指向執行個體
    // 箭頭函數内部的this總是指向定義時所在的對象
    resolve = (value) => {
        // 判斷狀态是不是
        if (this.status === STATUS_PENDING) {
            console.log("執行resolve");
            // 這裡接收傳進來的結果
            this.value = value;
            this.status = STATUS_FULFILLED;
            this.onFulfilledCallBacks.forEach((fn) => {
                fn();
            });
        }
    };
    reject = (reason) => {
        if (this.status === STATUS_PENDING) {
            console.log("執行reject");
            // 這裡接收傳進來的錯誤的結果
            this.reason = reason;
            this.status = STATUS_REJECTED;
            // 這裡相當于釋出的動作
            this.onRejectCallBacks.forEach((fn) => {
                fn();
            });
        }
    };

    then(onFulfilled, onReject) {
        onFulfilled =
            typeof onFulfilled === "function" ? onFulfilled : (value) => value;
        onReject = typeof onReject === "function" ? onReject : (reason) => reason;
        console.log("執行then時的狀态: ", this.status);
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === STATUS_FULFILLED) {
                // 這個地方使用settimeout的目的是擷取到promise2。因為setTimeout是異步的,
                // 會等到指派給promise2結束後才執行,
                // 這裡的resolvePromise的作用是為了區分x是普通值還是新的promise還是函數
                // 如果直接resolve(x)的話會導緻,輸出的是[object Object] res====,并不是想要的值
                setTimeout(() => {
                    // 這裡try進行了捕獲異常,在最外面的executor不是進行了捕獲了?
                    // 這是因為異步裡面的方法不會被最外層的那個捕獲到
                    try {
                        console.log("執行 onFulfilled");
                        //   這裡的x是啥? 是then中回調的return的傳回值
                        let x = onFulfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === STATUS_REJECTED) {
                setTimeout(() => {
                    try {
                        console.log("執行 onReject");
                        let x = onReject(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === STATUS_PENDING) {
                this.onFulfilledCallBacks.push(() =>
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                );
                this.onRejectCallBacks.push(() =>
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                );
            }
        });

        return promise2;
    }
}

// 下面的函數相當于釋出者
let t = new MyPromise((resolve, reject) => {
    // 指定執行哪個,resolve和reject最終隻會執行一個
    // console.log(a)  // 執行console會報錯,最終隻會執行reject
    // // resolve("res")
    // reject('reject')
    // setTimeout(() => {
    resolve("then鍊式調用");
    // }, 1000)
});
t.then(() => {
    return new MyPromise((resolve) => {
        console.log(2);
        setTimeout(() => {
            resolve(3);
        }, 3000);
    });
}).then(
    (res) => {
        console.log(res.toString(), "res====");
    },
    (error) => {
        console.log(error);
    }
);