Promise的源碼實現(符合Promise/A+規範)

Promise的源碼實現

/**
 * 1. new Promise時,需要傳遞一個 executor 執行器,執行器立刻執行
 * 2. executor 接受兩個參數,分別是 resolve 和 reject
 * 3. promise 只能從 pending 到 rejected, 或者從 pending 到 fulfilled
 * 4. promise 的狀態一旦確認,就不會再改變
 * 5. promise 都有 then 方法,then 接收兩個參數,分別是 promise 成功的回調 onFulfilled, 
 *      和 promise 失敗的回調 onRejected
 * 6. 如果調用 then 時,promise已經成功,則執行 onFulfilled,並將promise的值作爲參數傳遞進去。
 *      如果promise已經失敗,那麼執行 onRejected, 並吧 promise 失敗的原因作爲參數傳遞進去。
 *      如果promise的狀態是pending,需要將onFulfilled和onRejected函數存放起來,等待狀態確定後,再依次將對應的函數執行(發佈訂閱)
 * 7. then 的參數 onFulfilled 和 onRejected 可以缺省
 * 8. promise 可以then多次,promise 的then 方法返回一個 promise
 * 9. 如果 then 返回的是一個結果,那麼就會把這個結果作爲參數,傳遞給下一個then的成功的回調(onFulfilled)
 * 10. 如果 then 中拋出了異常,那麼就會把這個異常作爲參數,傳遞給下一個then的失敗的回調(onRejected)
 * 11.如果 then 返回的是一個promise,那麼需要等這個promise,那麼會等這個promise執行完,promise如果成功,
 *   就走下一個then的成功,如果失敗,就走下一個then的失敗
 */

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function Promise(executor) {
    let self = this;
    self.status = PENDING;
    self.onFulfilled = [];//成功的回調
    self.onRejected = []; //失敗的回調
    //PromiseA+ 2.1
    function resolve(value) {
        if (self.status === PENDING) {
            self.status = FULFILLED;
            self.value = value;
            self.onFulfilled.forEach(fn => fn());//PromiseA+ 2.2.6.1
        }
    }

    function reject(reason) {
        if (self.status === PENDING) {
            self.status = REJECTED;
            self.reason = reason;
            self.onRejected.forEach(fn => fn());//PromiseA+ 2.2.6.2
        }
    }

    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}

Promise.prototype.then = function (onFulfilled, onRejected) {
    //PromiseA+ 2.2.1 / PromiseA+ 2.2.5 / PromiseA+ 2.2.7.3 / PromiseA+ 2.2.7.4
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
    let self = this;
    //PromiseA+ 2.2.7
    let promise2 = new Promise((resolve, reject) => {
        if (self.status === FULFILLED) {
            //PromiseA+ 2.2.2
            //PromiseA+ 2.2.4 --- setTimeout
            setTimeout(() => {
                try {
                    //PromiseA+ 2.2.7.1
                    let x = onFulfilled(self.value);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    //PromiseA+ 2.2.7.2
                    reject(e);
                }
            });
        } else if (self.status === REJECTED) {
            //PromiseA+ 2.2.3
            setTimeout(() => {
                try {
                    let x = onRejected(self.reason);
                    resolvePromise(promise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            });
        } else if (self.status === PENDING) {
            self.onFulfilled.push(() => {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(self.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                });
            });
            self.onRejected.push(() => {
                setTimeout(() => {
                    try {
                        let x = onRejected(self.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                });
            });
        }
    });
    return promise2;
}

function resolvePromise(promise2, x, resolve, reject) {
    let self = this;
    //PromiseA+ 2.3.1
    if (promise2 === x) {
        reject(new TypeError('Chaining cycle'));
    }
    if (x && typeof x === 'object' || typeof x === 'function') {
        let used; //PromiseA+2.3.3.3.3 只能調用一次
        try {
            let then = x.then;
            if (typeof then === 'function') {
                //PromiseA+2.3.3
                then.call(x, (y) => {
                    //PromiseA+2.3.3.1
                    if (used) return;
                    used = true;
                    resolvePromise(promise2, y, resolve, reject);
                }, (r) => {
                    //PromiseA+2.3.3.2
                    if (used) return;
                    used = true;
                    reject(r);
                });

            }else{
                //PromiseA+2.3.3.4
                if (used) return;
                used = true;
                resolve(x);
            }
        } catch (e) {
            //PromiseA+ 2.3.3.2
            if (used) return;
            used = true;
            reject(e);
        }
    } else {
        //PromiseA+ 2.3.3.4
        resolve(x);
    }
}

module.exports = Promise;

有專門的測試腳本可以測試所編寫的代碼是否符合PromiseA+的規範。

首先,在promise實現的代碼中,增加以下代碼:


Promise.defer = Promise.deferred = function () {
    let dfd = {};
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}

安裝測試腳本:

npm install -g promises-aplus-tests

如果當前的promise源碼的文件名爲promise.js

那麼在對應的目錄執行以下命令:

promises-aplus-tests promise.js

promises-aplus-tests中共有872條測試用例。以上代碼,可以完美通過所有用例。

以下附上PromiseA+的規範(自己隨便翻譯了下)

術語
  1. promise 是一個有then方法的對象或者是函數,行爲遵循本規範
  2. thenable 是一個有then方法的對象或者是函數
  3. value 是promise狀態成功時的值,包括 undefined/thenable或者是 promise
  4. exception 是一個使用throw拋出的異常值
  5. reason 是promise狀態失敗時的值
要求

2.1 Promise States

Promise 必須處於以下三個狀態之一: pending, fulfilled 或者是 rejected

2.1.1 如果promise在pending狀態

2.1.1.1 可以變成 fulfilled 或者是 rejected
2.1.2 如果promise在fulfilled狀態

2.1.2.1 不會變成其它狀態

2.1.2.2 必須有一個value值
2.1.3 如果promise在rejected狀態

2.1.3.1 不會變成其它狀態

2.1.3.2 必須有一個promise被reject的reason

概括即是:promise的狀態只能從pending變成fulfilled,或者從pending變成rejected.promise成功,有成功的value.promise失敗的話,有失敗的原因

2.2 then方法

promise必須提供一個then方法,來訪問最終的結果

promise的then方法接收兩個參數

promise.then(onFulfilled, onRejected)
2.2.1 onFulfilled 和 onRejected 都是可選參數
2.2.1.1 onFulfilled 必須是函數類型

2.2.1.2 onRejected 必須是函數類型
2.2.2 如果 onFulfilled 是函數:
2.2.2.1 必須在promise變成 fulfilled 時,調用 onFulfilled,參數是promise的value
2.2.2.2 在promise的狀態不是 fulfilled 之前,不能調用
2.2.2.3 onFulfilled 只能被調用一次
2.2.3 如果 onRejected 是函數:
2.2.3.1 必須在promise變成 rejected 時,調用 onRejected,參數是promise的reason
2.2.3.2 在promise的狀態不是 rejected 之前,不能調用
2.2.3.3 onRejected 只能被調用一次
2.2.4 onFulfilled 和 onRejected 應該是微任務
2.2.5 onFulfilled 和 onRejected 必須作爲函數被調用
2.2.6 then方法可能被多次調用
2.2.6.1 如果promise變成了 fulfilled態,所有的onFulfilled回調都需要按照then的順序執行
2.2.6.2 如果promise變成了 rejected態,所有的onRejected回調都需要按照then的順序執行
2.2.7 then必須返回一個promise
promise2 = promise1.then(onFulfilled, onRejected);
2.2.7.1 onFulfilled 或 onRejected 執行的結果爲x,調用 resolvePromise
2.2.7.2 如果 onFulfilled 或者 onRejected 執行時拋出異常e,promise2需要被reject
2.2.7.3 如果 onFulfilled 不是一個函數,promise2 以promise1的值fulfilled
2.2.7.4 如果 onRejected 不是一個函數,promise2 以promise1的reason rejected

2.3 resolvePromise

resolvePromise(promise2, x, resolve, reject)

2.3.1 如果 promise2 和 x 相等,那麼 reject promise with a TypeError
2.3.2 如果 x 是一個 promsie
2.3.2.1 如果x是pending態,那麼promise必須要在pending,直到 x 變成 fulfilled or rejected.
2.3.2.2 如果 x 被 fulfilled, fulfill promise with the same value.
2.3.2.3 如果 x 被 rejected, reject promise with the same reason.
2.3.3 如果 x 是一個 object 或者 是一個 function
2.3.3.1 let then = x.then.
2.3.3.2 如果 x.then 這步出錯,那麼 reject promise with e as the reason..
2.3.3.3 如果 then 是一個函數,then.call(x, resolvePromiseFn, rejectPromise)
    2.3.3.3.1 resolvePromiseFn 的 入參是 y, 執行 resolvePromise(promise2, y, resolve, reject);
    2.3.3.3.2 rejectPromise 的 入參是 r, reject promise with r.
    2.3.3.3.3 如果 resolvePromise 和 rejectPromise 都調用了,那麼第一個調用優先,後面的調用忽略。
    2.3.3.3.4 如果調用then拋出異常e 
        2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已經被調用,那麼忽略
        2.3.3.3.4.3 否則,reject promise with e as the reason
2.3.3.4 如果 then 不是一個function. fulfill promise with x.
2.3.4 如果 x 不是一個 object 或者 function,fulfill promise with x.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章