用ES6實現符合promise/A+規範的Promise

akirastorm發表於2018-01-16

ES6Promise

實現一個符合 Promise/A+ 規範的ES6寫法的Promise,並實現 resolve、reject、all、race等靜態方法。

Constructor(構造器)

  1. 作用:從建構函式 Promise 來建立一個新建新 promise 物件,可以使用 new 來呼叫 Promise的構造器來進行例項化
  2. 接收一個回撥函式 executor
  3. 狀態
    • 如果是pending狀態,則promise
      • 可以轉換到fulfilledrejected狀態。
    • 如果是fulfilled狀態,則promise
      • 不能轉換成任何其它狀態。
      • 必須有一個值,且這個值不能被改變。
    • 如果是rejected狀態,則promise可以:
      • 不能轉換成任何其它狀態。
  4. resolve
    • promise的狀態是fulfilled異常是的處理函式
    • 接收 value 引數
      • 如果是promise,執行then
      • 如果不是promise,把value做為引數傳給onFulfilledCallbacks裡的每個函式。
  5. reject
    • promise的狀態是rejected異常是的處理函式
    • 接收 reason 引數,把reason做為引數傳給onRejectedCallbacks裡的每個函式。
  6. 執行 executor,如果有異常,拋給reject
    constructor(executor) {
        if (typeof executor !== 'function') {
            throw new TypeError('Promise resolver ' + executor + ' is not a function');
        }

        let self = this
        this.status = 'pending'
        this.value = undefined
        this.reason = undefined
        this.onFulfilledCallbacks = []
        this.onRejectedCallbacks = []

        function resolve (value) {
            if (value instanceof ES6Promise) {
                return value.then(resolve, reject);
            }
            if (self.status === 'pending') {
                self.value = value;
                self.status = 'fulfilled';
                self.onFulfilledCallbacks.forEach(item => item(value));
            }
        }

        function reject(reason) {
            if (self.status === 'pending') {
                self.reason = reason;
                self.status = 'rejected';
                self.onRejectedCallbacks.forEach(item => item(reason));
            }
        }

        try {
            executor(resolve, reject)
        } catch (e) {
            reject(e)
        }
    }  
複製程式碼

Instance Method(內建方法)

  • resolvePromise(私有方法)

    1. Promise解析過程 是以一個promise和一個值做為引數的抽象過程,可表示為[[Resolve]](promise, x)

    2. 如果promisex 指向相同的值, 使用 TypeError做為原因將promise拒絕。

    3. 如果 x 是一個promise, 採用其狀態:

      • 如果xpending狀態,promise必須保持pending走到x fulfilledrejected.
      • 如果xfulfilled狀態,將x的值用於fulfill promise.
      • 如果xrejected狀態, 將x的原因用於reject promise.
    4. 如果x是一個物件或一個函式:

      • then 賦為 x.then.
      • 如果在取x.then值時丟擲了異常,則以這個異常做為原因將promise拒絕。
      • 如果 then 是一個函式, 以xthis呼叫then函式, 且第一個引數是resolvePromise,第二個引數是rejectPromise,且:
        • resolvePromise 被以 y為引數呼叫, 執行 [[Resolve]](promise, y).
        • rejectPromise 被以 r為引數呼叫, 則以r為原因將promise拒絕。
        • 如果 resolvePromiserejectPromise 都被呼叫了,或者被呼叫了多次,則只第一次有效,後面的忽略。
        • 如果在呼叫then時丟擲了異常,則: * 如果 resolvePromiserejectPromise 已經被呼叫了,則忽略它。 * 否則, 以ereasonpromise拒絕。
      • 如果 then 不是一個函式,則 以x 為值fulfill promise
    5. 如果 x 不是物件也不是函式,則以x為值 fulfill promise

    //利用Symbol值的唯一性,將私有方法的名字命名為一個Symbol值
    const _resolvePromise = Symbol('resolvePromise')

    [_resolvePromise](promise2, x, resolve, reject) {
        let self = this
        if (promise2 === x) {
            return reject(new TypeError('迴圈引用'))
        }
        let then, called
        
        if (x != null && ((typeof x == 'object' || typeof x == 'function'))) {
            try {
            then = x.then
            if (typeof then == 'function') {
                then.call(x, function (y) {
                if (called)return
                called = true
                self[_resolvePromise](promise2, y, resolve, reject)
                }, function (r) {
                if (called)return
                called = true
                reject(r)
                });
            } else {
                resolve(x)
            }
            } catch (e) {
            if (called)return
            called = true
            reject(e)
            }
        } else {
            resolve(x)
        }
    }
複製程式碼

==以下未完待填坑==

  • then

  • catch

Static Method(靜態方法)

  • all

  • race

  • resolve

  • reject

參考資料
  • https://segmentfault.com/a/1190000002452115
  • http://liubin.org/promises-book/

相關文章