根據Promise/A+規範實現Promise

根據Promise/A+規範實現Promise

Promise/A+規範實現Promise,promises-aplus-tests測試經過。數組

const PENDING = "PENDING"
const FULFILLED = "FULFILLED"
const REJECTED = "REJECTED"
const resolvePromise = (promise2, x, resolve, reject) => {
  if (promise2 === x) {
    return reject(new TypeError(`Chaining cycle detected for promise #<Promise>`));
  }
  if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
    let then, called;
    try {
      then = x.then;
      if (typeof then === 'function') {
        then.call(x, y => {
          if (called) return;
          called = true
          resolvePromise(promise2, y, resolve, reject)
        }, r => {
          if (called) return;
          called = true
          reject(r)
        })
      } else {
        resolve(x)
      }
    } catch (e) {
      if (called) return;
      called = true
      reject(e)
    }
  } else {
    resolve(x)
  }
}
const isPromise = (value) => {
  if ((typeof value === 'object' && value !== null) || typeof value === 'function') {
    return typeof value.then === 'function'
  }
  return false
}
class Promise {
  constructor(executor) {
    this.status = PENDING
    this.value = undefined
    this.reason = undefined
    this.onFulfilledCallBack = []
    this.onRejectedCallBack = []
    const resolve = (value) => {
      if (value instanceof Promise) {
        return value.then(resolve, reject)
      }
      if (this.status === PENDING) {
        this.status = FULFILLED
        this.value = value
        this.onFulfilledCallBack.forEach(fn => fn())
      }
    }
    const reject = (reason) => {
      if (this.status === PENDING) {
        this.status = REJECTED
        this.reason = reason
        this.onRejectedCallBack.forEach(fn => fn())
      }
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => { return value; }
    onRejected = typeof onRejected === 'function' ? onRejected : (err) => { throw err; }
    let promise2 = new Promise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          try {
            const x = onFulfilled(this.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            const x = onRejected(this.reason)
            resolvePromise(promise2, x, resolve, reject)
          } catch (e) {
            reject(e)
          }
        })
      }
      if (this.status === PENDING) {
        this.onFulfilledCallBack.push(() => {
          setTimeout(() => {
            try {
              const x = onFulfilled(this.value)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
        this.onRejectedCallBack.push(() => {
          setTimeout(() => {
            try {
              const x = onRejected(this.reason)
              resolvePromise(promise2, x, resolve, reject)
            } catch (e) {
              reject(e)
            }
          })
        })
      }
    })
    return promise2
  }
  catch(errCallBack) {
    return this.then(null, errCallBack)
  }
  finally(callback) {
    return this.then(value => {
      return Promise.resolve(callback()).then(() => value)
    }, err => {
      return Promise.resolve(callback()).then(() => { throw err; })
    })
  }
  static resolve(value) {
    return new Promise((resolve, reject) => {
      resolve(value)
    })
  }
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }
  static all(promises) {
    return new Promise((resolve, reject) => {
      let arr = [], i = 0;
      let processData = (index, data) => {
        arr[i] = data
        if (++i === promises.length) {
          resolve(arr)
        }
      }
      if (promises instanceof Array) {
        promises.forEach((p, index) => {
          if (isPromise(p)) {
            p.then((data) => {
              processData(index, data)
            }, reject)
          } else {
            processData(index, p)
          }
        })
      } else {
        reject()
      }
    })
  }
  static race(promises) {
    return new Promise((resolve, reject) => {
      if (promises instanceof Array) {
        for (let i = 0; i < promises.length; i++) {
          let current = promises[i]
          if (isPromise(current)) {
            if (current.value || (!isPromise(current.value) && current.status !== PENDING)) {
              resolve(current.value)
            }
            current.then(resolve, reject)
          } else {
            resolve(current)
          }
        }
      } else {
        reject()
      }
    })
  }
  static try(callback) {
    return new Promise((resolve, reject) => {
      return Promise.resolve(callback()).then(resolve)
    })
  }
}
Promise.deferred = function () {
  let dfd = {};
  dfd.promise = new Promise((resolve, reject) => {
    dfd.resolve = resolve;
    dfd.reject = reject
  })
  return dfd;
}
module.exports = Promise
/**
 * 根據Promise/A+規範
 * 實現Promise步驟解析:
 * 1.Promise的構造函數接收一個函數
 *  executor(resolve, reject)
 *   接收2個參數
 *      resolve 成功後執行函數,改變value和status
 *      reject  失敗後執行函數,改變reason和status
 * 注意:
 *    1.一旦建立它就會當即執行,中途沒法取消
 *    2.一旦狀態改變就不會在變
 *    3.若是resolve接收的是一個promise,就讓它執行then方法而且採用它的狀態
 *    4.若是拋出異常,須要處理異常狀況
 * 2.Promise實例生成後,用then方法指定fulfilled 和 rejected狀態的回調
 *    1).同步函數
 *        直接判斷status的狀態,分別調用onFulfilled或onRjected
 *    2).異步函數
 *        須要用到訂閱發佈模式
 *        定義兩個數組分別保存fulfilled 和 rejected的回調函數,
 *          再異步執行到resolve或reject的時候,
 *          改變狀態獲取value或reason,
 *          再去執行數組中保存的回調函數
 * 3.promise的鏈式調用
 *    特色:
 *      1).then中返回一個新的promise對象
 *        promise2 = new Promise(executor);
          return promise2;
 *      2).鏈式調用中,下一個then的狀態採用它上一個then的返回
 *          須要保存第一個then返回的值,
 *          a.若是第一個then返回的是普通值(除function,object),會走下一個then的成功
 *          b.若是第一個then拋出錯誤,會走下一個then的失敗
 *          c.若是第一個then返回的是一個promise,就讓它執行而且採用它的狀態
 *              此過程須要遞歸,直到再沒有promise爲止
 * 注意:
 *    1.onFulfilled 和 onRejected 不能在當前上下文執行
 *      解決辦法:使用setTimeout
 *        使用setTimeout的還有一個目的:保證能拿到promise2
 *    2.then中2個回調都不存在時的處理
 *      解決辦法:不存在時,須要本身提供默認的函數
 * 4.catch的實現
 *     catch的原理:成功回調函數爲null時的then方法
 *     then(null,onRejected)
 * 5.all
 *    原理:
 *      1).返回一個新的Promise實例(全部的都成功才成功,有一個失敗就失敗)
 *      2).接收一個數組,數組中都是Promise實例,
 *          若是不是,就會先調用Promise.resolve方法,將參數轉爲 Promise 實例,再進一步處理。
 *      3).只有數組中全部的promise的狀態都變成fulfilled,狀態纔會變成fulfilled,返回值組成一個數組,傳遞給外層的回調函數。
        4).只要數組中有一個是rejected,狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給外層的回調函數。
 * 6.finally
    原理:
      1).不管如何都執行
      若是回調函數中返回promise,等待promise執行完畢,再走下一個then/catch(捕獲finally上一個then的成功和失敗)
 * 7.race
 *    原理:
 *      1).返回一個新的Promise實例
 *      2).接收一個數組,數組中都是Promise實例,
 *          若是不是,就會先調用Promise.resolve方法,將參數轉爲 Promise 實例,再進一步處理。
 *      3).promise數組中誰快返回誰的結果 * 
 * 8.Promise.resolve和Promise.reject的實現
 *    Promise.resolve原理:返回一個成功的Promise
 *    Promise.reject原理:返回一個失敗的Promise
 * 9.Promise.try
 *    原理:
 *      1).無論是同步仍是異步錯誤都能捕獲
 */
複製代碼
相關文章
相關標籤/搜索