Promise 简单实现

2019-05-20  本文已影响0人  Mica_马超
function Promise(fn) {

  let state = 'pending'
  let value = null
  let queue = []

  this.then = function(onResolver, onRejecter) {
    return new Promise(function(resolve, reject) {
      handle({
        onResolver: onResolver || null,
        onRejecter: onRejecter || null,
        resolve,
        reject
      })
    })
  }

  this.all = promises => new Promise((resolve, reject) => {
    let result = []

    let length = promises.length

    let count = length

    let index = 0

    const allResolver = (index, value) => {
      result[index] = value

      while(--count === 0) {
        resolve(result)
      }
    }

    const myResolver = index => value => allResolver(index, value)

    const myRejecter = wtf => reject(wtf)

    for(; index < length; index++) {
      promises[index].then(myResolver(index), myRejecter)
    }
  })

  function handle(callback) {

    // fn 异步, 则先放进队列, 稍后执行, 否则 continue
    if(state === 'pending') {
      queue.push(callback)
      return
    }

    let ret

    let cb = state === 'fulfilled' ? callback.onResolver : callback.onRejecter

    // then === null, 穿透
    if(cb === null) {
       cb = state === 'fulfilled' ? callback.resolve : callback.reject
       cb(value)
       return
    }

    try {
      ret = cb(value)
      // next then
      callback.resolve(ret)
    } catch (e) {
      callback.reject(e)
    }
  }

  function resolve(newValue) {
    // 兼容第三方 Promise 实现
    if(newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
      let _then = newValue.then
      if(typeof _then === 'function') {
        _then.call(newValue, resolve, reject)
        return
      }
    }

    state = 'fulfilled'

    value = newValue

    execute()
  }

  function reject(reason) {
    state = 'rejected'
    value = reason
    execute()
  }

  function execute() {
    // 如果 fn 为同步方法, 则此时 callback queue 队列还为空, 所以需要放到次轮循环
    setTimeout(() => {
      queue.forEach(callback => {
        handle(callback)
      })
    }, 0)
  }

  try {
    fn(resolve, reject)
  } catch (e) {
    reject(e)
  }
}
上一篇 下一篇

猜你喜欢

热点阅读