理解Promise

57 阅读5分钟

理解Promise

不考虑参照Promises/A+规范,不考虑任何异常情况;主要关注核心逻辑实现一个Promise。

构造一个Promise对象

设想

// Promise构造函数接收一个executor函数,executor函数执行完同步或异步操作后,调用它的两个参数resolve和reject
let promise = new Promise(function(resolve, reject) {
  /*
    如果操作成功,调用resolve并传入value
    如果操作失败,调用reject并传入reason
  */
})

大概思路

  • 实例化时用户传入自定义fn,fn内部会做逻辑判断(成功/失败)。成功/失败修改实例中的对应的属性。

  • 在自定义fn调用时,让成功/失败的方法作为fn参数,用户就可以在fn内部使用成功/失败的方法

JS代码

const STATUS = {
  PENDING: 'pending',
  RESOLVED: 'resolved',
  REJECTED: 'rejected',
}

class MyPromise {
  constructor(executor) {
    // 被resolved的值
    this._value = undefined;
    // 被rejected的值
    this._reason = undefined;
    this._state = STATUS.PENDING;

    if (executor) {
      //  TODO: 简单的异步处理 可优化
      setTimeout(() => {
        // TODO: executor是用户传入的函数,考虑到执行executor的过程中有可能出错,所以可以考虑try/catch块给包起来
        // 执行executor时,bind()保证resolve,reject内部this!=undefined
        executor(this._onResolved.bind(this), this._onRejected.bind(this))
      })
    }
  }

  _onResolved(value) {
    const {_state,} = this
    const {PENDING, RESOLVED} = STATUS
    if (_state === PENDING) { // 确保_state只会修改一次
      this._value = value
      this._state = RESOLVED
    }
  }

  _onRejected(reason) {
    const {_state, _reason} = this
    const {PENDING, REJECTED} = STATUS
    if (_state === PENDING) { // 确保_state只会修改一次
      this._reason = reason
      this._state = REJECTED
    }
  }
}

实现核心的功能异步链式调用(then)

设想

// 调用then并传入onResolved或onRejected 方法,将return值作为下一个then的onResolved参数,并且then()的返回值是promise。
let promise2 = promise.then(
		function(res) {return res }, // 如果操作成功,调用onResolved
		function(err) {return err }, //如果操作失败,调用onRejected
	).then(
    res => {}) // 上一个then的返回值

// promise2 = Promise{}

大概思路

  • 调用then时(如:xxx.then( ()=>1,()=>2 )),新增MyPromise类作为当前then操作的对象,将fn1/fn2作为成功/失败的回调;

  • 开始收集依赖,用于数据传递

  • 根据当前MyPromise实例的status,判断成功/失败,并将值传递给下一个;本质上就是更新最新的MyPromise类的属性值

this.thenQueue.forEach(([nextPromise, onResolved,]) => {
	if (onResolved) {
// 将当前实例的值,作为then的resolve回调的参数,这样then内部就能够获取到
		const valueOrPromise = onResolved(this._value); 
// 将传入的值更新到最新的MyPromise类内部,以便传递给下一个then      
		if (isThenable(valueOrPromise)) { // Promise处理
			valueOrPromise.then(
				value => nextPromise._onResolved(value),
				reason => nextPromise._onResolved(reason)
			)
 	} else { // 非Promise
			nextPromise._onResolved(valueOrPromise)
		}
	} else { 
		nextPromise._onResolved(this._value)
	}
})

JS代码

  _onResolved(value) {
    const {_state,} = this
    const {PENDING, RESOLVED} = STATUS
    if (_state === PENDING) { 
      this._value = value
      this._state = RESOLVED
      this._handleResolvedQueue() // 对Resolved的处理
    }
  }

  _onRejected(reason) {
    const {_state,} = this
    const {PENDING, REJECTED} = STATUS
    if (_state === PENDING) { 
      this._reason = reason
      this._state = REJECTED
      this._handleRejectedQueue() // 对Rejected的处理
    }
  }

  then(onResolved, onRejected) {
    const {_state, _thenQueue} = this
    const {RESOLVED, REJECTED} = STATUS
    const nextPromise = new MyPromise()
    // 对nextPromise, onResolved, onRejected进行收集;
    this._thenQueue.push([nextPromise, onResolved, onRejected]);

    if (_state === RESOLVED) {
      this._handleResolvedQueue()
    } else if (_state === REJECTED) {
      this._handleRejectedQueue()
    }
    return nextPromise
  }

  // 对Resolved的处理
  _handleResolvedQueue() {
    const {_value,} = this
    // 收集好的onResolved
    this._thenQueue.forEach(([nextPromise, onResolved,]) => {
        if (onResolved) {
          // 对上一次的then中 return new MyPromise(...) / return value ?
          // TODO: onResolved 是可能会出错的 handle err
          const valueOrPromise = onResolved(_value)
          if (isThenable(valueOrPromise)) { // Promise处理
            valueOrPromise.then(
              value => nextPromise._onResolved(value),
              reason => nextPromise._onResolved(reason)
            )
          } else { // 非Promise,将值传递给下一个
            nextPromise._onResolved(valueOrPromise)
          }
        } else { // 如果.then中没有传入resolve方法,则只是对上一个Promise的resolved的值中转,传给下一个
          nextPromise._onResolved(_value)
        }
      }
    )

    // 重置_thenQueue
    this._thenQueue = []
  }

  // 对Rejected的处理
  _handleRejectedQueue() {
    const {_reason} = this
    // 收集好的onRejected
    this._thenQueue.forEach(([nextPromise, _, onResolved,]) => {
        if (onResolved) {
          // 对上一次的then中 return new MyPromise(...) / return value ?
          // TODO: onResolved 是可能会出错的 handle err
          const valueOrPromise = onResolved(_reason)
          if (isThenable(valueOrPromise)) { // Promise处理
            valueOrPromise.then(
              value => nextPromise._onRejected(value),
              reason => nextPromise._onRejected(reason)
            )
          } else { // 非Promise,此时需要将值以Resolved的状态传递给下一个
            nextPromise._onResolved(valueOrPromise)
          }
        } else { // 如果.then中没有传入resolve方法,则只是对上一个Promise的resolved的值中转,传给下一个
          nextPromise._onRejected(_reason)
        }
      }
    )

    // 重置_thenQueue
    this._thenQueue = []
  }

案例

const p0 = new MyPromise((resolve, reject) => {
  // resolve(1)
  reject(2)
})

console.log("开始")
p0.then(
  res => {
    console.log("res==>", res)
    return 200
  },
  err => {
    console.log("err==>", err)
    return 404
  })
  .then(res => {
    console.log("nextThen==>", res)
  })
console.log("结束")

// 开始
// 结束
// res==> 1  or  err==> 2
// nextThen==> 200  or  nextThen==> 404

正确的输出顺序应该是 res和nextThen 应该再开始-结束中间,由于我们做了简单的异步处理,优化也很简单,把异步操作放到_handleResolvedQueue和_handleResolvedQueue即可。

catch的实现

本质上是基于then方法的实现

 catch(Rejected) {
    return this.then(undefined, Rejected)
  }

finally实现

与then的原理类似

  finally(sideEffect) {
    const {_state, _value} = this
    const {PENDING, RESOLVED} = STATUS

    if (_state !== PENDING) {
      if (sideEffect) {
        // TODO: 副作用函数是有可能出错的 handle error
        sideEffect()
      }
      return _state === RESOLVED ? MyPromise.resolve(_value) : MyPromise.reject(_value)
    } else {
      const nextPromise = new MyPromise()
      this._finallyQueue.push([nextPromise, sideEffect]);
      return nextPromise
    }
  }

完整代码

const STATUS = {
  PENDING: 'pending',
  RESOLVED: 'resolved',
  REJECTED: 'rejected',
}

// 是否MyPromise类型
const isThenable = (val) => val && (typeof val.then === 'function');

class MyPromise {
  constructor(executor) {
    // 被resolved的值
    this._value = undefined;
    // 被rejected的值
    this._reason = undefined;
    this._state = STATUS.PENDING;
    // 收集对应返回的Promise以及处理函数
    this._thenQueue = [];
    // 收集副作用函数
    this._finallyQueue = [];

    // TODO: executor是用户传入的函数,考虑到执行executor的过程中有可能出错,所以可以考虑try/catch块给包起来
    if (executor) {
      // 执行executor时,为保证resolve,reject内部this!=undefined
      executor(this._onResolved.bind(this), this._onRejected.bind(this))
    }
  }

  _onResolved(value) {
    const {_state,} = this
    const {PENDING, RESOLVED} = STATUS
    if (_state === PENDING) { // 确保_state只会修改一次
      this._value = value
      this._state = RESOLVED
      this._handleResolvedQueue()
    }
  }

  _onRejected(reason) {
    const {_state,} = this
    const {PENDING, REJECTED} = STATUS
    if (_state === PENDING) { // 确保_state只会修改一次
      this._reason = reason
      this._state = REJECTED
      this._handleRejectedQueue()
    }
  }

  then(onResolved, onRejected) {
    const {_state, _thenQueue} = this
    const {RESOLVED, REJECTED} = STATUS
    const nextPromise = new MyPromise()
    // 对nextPromise, onResolved, onRejected进行收集;
    this._thenQueue.push([nextPromise, onResolved, onRejected]);

    if (_state === RESOLVED) {
      this._handleResolvedQueue()
    } else if (_state === REJECTED) {
      this._handleRejectedQueue()
    }
    return nextPromise
  }

  // 对Resolved的处理
  _handleResolvedQueue() {
    //  TODO: 简单的异步处理 可优化
    setTimeout(() => {
      const {_value,} = this

      // 收集好的onResolved
      this._thenQueue.forEach(([nextPromise, onResolved,]) => {
          if (onResolved) {
            // 对上一次的then中 return new MyPromise(...) / return value ?
            // TODO: onResolved 是可能会出错的 handle err
            const valueOrPromise = onResolved(_value)
            if (isThenable(valueOrPromise)) { // Promise处理
              valueOrPromise.then(
                value => nextPromise._onResolved(value),
                reason => nextPromise._onResolved(reason)
              )
            } else { // 非Promise,将值传递给下一个
              nextPromise._onResolved(valueOrPromise)
            }
          } else { // 如果.then中没有传入resolve方法,则只是对上一个Promise的resolved的值中转,传给下一个
            nextPromise._onResolved(_value)
          }
        }
      )

      this._finallyQueue.forEach(([nextPromise, sideEffect]) => {
        if (sideEffect) {
          // TODO: 副作用函数是有可能出错的 handle error
          sideEffect()
        }
        nextPromise._onResolved(_value)
      })

      // 重置_thenQueue
      this._thenQueue = []
      this._finallyQueue = []
    })
  }

  // 对Rejected的处理
  _handleRejectedQueue() {
    //  TODO: 简单的异步处理 可优化
    setTimeout(() => {
      const {_reason} = this
      // 收集好的onRejected
      this._thenQueue.forEach(([nextPromise, _, onResolved,]) => {
          if (onResolved) {
            // 对上一次的then中 return new MyPromise(...) / return value ?
            // TODO: onResolved 是可能会出错的 handle err
            const valueOrPromise = onResolved(_reason)
            if (isThenable(valueOrPromise)) { // Promise处理
              valueOrPromise.then(
                value => nextPromise._onRejected(value),
                reason => nextPromise._onRejected(reason)
              )
            } else { // 非Promise,此时需要将值以Resolved的状态传递给下一个
              nextPromise._onResolved(valueOrPromise)
            }
          } else { // 如果.then中没有传入resolve方法,则只是对上一个Promise的resolved的值中转,传给下一个
            nextPromise._onRejected(_reason)
          }
        }
      )

      this._finallyQueue.forEach(([nextPromise, sideEffect]) => {
        if (sideEffect) {
          // TODO: 副作用函数是有可能出错的 handle error
          sideEffect()
        }
        nextPromise._onRejected(_reason)
      })

      // 重置_thenQueue
      this._thenQueue = []
      this._finallyQueue = []
    })
  }

  catch(Rejected) {
    return this.then(undefined, Rejected)
  }

  finally(sideEffect) {
    const {_state, _value} = this
    const {PENDING, RESOLVED} = STATUS

    if (_state !== PENDING) {
      if (sideEffect) {
        // TODO: 副作用函数是有可能出错的 handle error
        sideEffect()
      }
      return _state === RESOLVED ? MyPromise.resolve(_value) : MyPromise.reject(_value)
    } else {
      const nextPromise = new MyPromise()
      this._finallyQueue.push([nextPromise, sideEffect]);
      return nextPromise
    }
  }
}

MyPromise.resolve = (value) => {
  return new MyPromise((resolve, reject) => {
    resolve(value)
  })
}

MyPromise.reject = (value) => {
  return new MyPromise((resolve, reject) => {
    reject(value)
  })
}

总结

  • 核心是then方法的实现,其他方法是对promise的扩充。
  • 本文只是简单实现一个初步的 promise,而真正的 promise 比它复杂很多,涉及到各种异常情况、边界情况的处理。

最后一句

学习心得!若有不正,还望斧正。希望掘友们不要吝啬对我的建议。