手動實現完整的Promise

聲明:本文是學習珠峯培訓視頻,模仿實現的Promise,通過了 promises-aplus-tests測試,文章最下面有截圖。

const PENDING = 'pending'; // 初始態

const FULFILLED = 'fulFilled'; // 成功態

const REJECTED = 'rejected'; // 失敗態

 

function Promise(exector) {

    let self = this; // 先緩存當前的 Promise實例

    self.status = PENDING; // 設置狀態

    self.onResolvedCallbacks = []; // 定義存放成功回調的數組

    self.onRejectedCallbacks = []; // 定義存放失敗回調的數組

 

    function resolve(value) {

        if (value instanceof Promise) {

            return value.then(resolve, reject);

        }

        //  當調用此方法的時候,如果是pending狀態,則轉成 成功態

        if (self.status === PENDING) {

            self.status = FULFILLED;

            self.value = value; // 成功後會得到一個值,這個值不能改

            // 調用所有成功的回調

            self.onResolvedCallbacks.forEach(cb => cb(self.value))

        }

    }

 

    function reject(reason) {

        // 如果是初始態,則轉成失敗態

 

        if (self.status === PENDING) {

            self.status = REJECTED;

            self.value = reason; // 失敗的原因 給value

            // 調用所有失敗的回調

            self.onRejectedCallbacks.forEach(cb => cb(self.value))

        }

    }

    try {

        exector(resolve, reject); // 因爲此函數執行的時候,可能出異常,所以需要捕獲,如果出錯了,需要用錯誤對象Reject

    } catch (e) {

        reject(e); // 如果執行失敗了,用失敗的原因reject這個Promise

    }

 

}

// onFulfilled用來接收Promise成功的值或失敗的原因

Promise.prototype.then = function (onFulfilled, onRejected) {

    // 如果成功和失敗的回調沒有傳,則表示這個then沒有任何邏輯,只會把值往後拋

    onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : value => value;

    onRejected = typeof onRejected == 'function' ? onRejected : reason => {

        throw reason

    };

    let self = this;

    let promise2;

    // 如果當前的Promise狀態已經是成功態了,onFulfilled直接取值

    if (self.status == FULFILLED) {

        return promise2 = new Promise(function (resolve, reject) {

            setTimeout(function () {

                try {

                    let x = onFulfilled(self.value)

                    // 如果獲取到了返回值,會走解析Promise的過程

                    resolvePromise(promise2, x, resolve, reject);

                } catch (e) {

                    // 如果執行成功的回調中出問題了,用錯誤原因把promise2 reject

                    reject(e);

                }

            })

 

        })

    }

    if (self.status == REJECTED) {

        return promise2 = new Promise(function (resolve, reject) {

            setTimeout(function () {

                try {

                    let x = onRejected(self.value);

                    resolvePromise(promise2, x, resolve, reject);

                } catch (e) {

                    reject(e);

                }

            })

        })

 

    }

    if (self.status == PENDING) {

        return promise2 = new Promise(function (resolve, reject) {

            self.onResolvedCallbacks.push(function () {

                setTimeout(function () {

                    try {

                        let x = onFulfilled(self.value);

                        resolvePromise(promise2, x, resolve, reject);

                    } catch (e) {

                        reject(e);

                    }

                })

 

            })

            self.onRejectedCallbacks.push(function () {

                setTimeout(function () {

                    try {

                        let x = onRejected(self.value);

                        resolvePromise(promise2, x, resolve, reject);

                    } catch (e) {

                        reject(e);

                    }

                })

 

            })

        })

 

    }

 

    function resolvePromise(promise2, x, resolve, reject) {

        if (promise2 === x) {

            return reject(new TypeError('循環引用'));

        }

        let called = false; // 用於判斷promise2是否已經resolve或reject

        // if (x instanceof Promise) {

        //     if (x.status === PENDING) {

        //         setTimeout(function () {

        //             x.then(function (y) {

        //                 resolvePromise(promise2, 2, resolve, reject)

        //             }, function (e) {

        //                 reject(e)

        //             })

        //         })

 

        //     } else {

        //         setTimeout(function () {

        //             x.then(resolve, reject);

        //         })

        //     }

        //     // x 是一個 thenable對象或函數,只要有then方法的對象    

        // } else 

        if (x != null && ((typeof x == 'object') || (typeof x === 'function'))) {

            // 以下代碼 主要用於我們的Promise和別人的Promise進行交互,編寫這種代碼,要考慮到

            // 兼容性,允許別人出錯

            try {

                let then = x.then;

                if (typeof then == 'function') {

                    // 有些promise會同時執行成功和失敗的回調

                    then.call(x, function (y) {

                        // 如果promise2已經成功或者失敗了,則不需要再處理了

                        if (called) return;

                        called = true;

                        resolvePromise(promise2, y, resolve, reject);

                    }, function (err) {

                        if (called) return;

                        called = true;

                        reject(err);

                    })

                } else {

                    // 如果promise2已經成功或者失敗了,則不需要再處理了

                    if (called) return;

                    called = true;

                    // 到此的話 x 不是一個 thenable對象,那直接把他rosolve掉

                    resolve(x);

                }

            } catch (e) {

                if (called) return;

                called = true;

                reject(e);

            }

        } else {

            // 如果promise2已經成功或者失敗了,則不需要再處理了

            if (called) return;

            called = true;

            // 如果x 是一個普通的值,就用x的值去resolve promise2

            resolve(x)

        }

 

    }

}

Promise.prototype.catch = function (onRejected) {

    // catch 的原理就是隻傳失敗的回調

    this.then(null, onRejected);

}

Promise.deferred = Promise.defer = function () {

    let defer = {};

    defer.promise = new Promise(function (resolve, reject) {

        defer.resolve = resolve;

        defer.reject = reject;

    })

    return defer;

}

module.exports = Promise;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章