手写Promise源码,Promise原理解析

28 阅读9分钟

Promise/A+: www.ituring.com.cn/article/665…

Promise: github.com/then/promis…

asap: github.com/kriskowal/a…

首先看下原生Promise的用法


// 把下面代码放到控制台查看结果
new Promise((resolve,reject)=>{
    
}) // pending---undefined

// 把下面代码放到控制台查看结果
new Promise((resolve,reject)=>{
    resolve(1)
}) // fulfilled---1

// 把下面代码放到控制台查看结果
new Promise((resolve,reject)=>{
    reject(2)
}) // rejected---2

使用class写法

基础3步

class MyPromise {

  /**
   * 1,由于Promise是一个构造函数,所以需要实现constructor函数
   * 2,constructor函数接受一个回调函数executor,并且是同步执行的
   * 3,executor函数需要2个参数,
   * 一个是执行成功的resolve参数,
   * 一个是执行失败的reject参数,这2个参数都是函数,
   * 由于是在构造函数里执行的executor函数,
   * 所以resolve和reject这2个函数参数需要在这里定义,
   * 并传递给executor函数执行
   */
  constructor(executor){

    function resolve(value){

    }

    function reject(reason){

    }

    executor(resolve, reject)
  }
}

第4步,实现resolve和reject函数

// 定义Promise的3种状态
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MyPromise {

  // 初始状态为pending
  #PromiseState = PENDING
  #PromiseResult = undefined

  /**
   * 1,由于Promise是一个构造函数,所以需要实现constructor函数
   * 2,constructor函数接受一个回调函数executor,并且是同步执行的
   * 3,executor函数需要2个参数,
   * 一个是执行成功的resolve参数,
   * 一个是执行失败的reject参数,
   * 这2个参数都是函数,由于是在构造函数里执行的executor函数,
   * 所以resolve和reject这2个函数参数需要在这里定义,并传递给executor函数执行
   * 4,resolve和reject函数是Promise提供的,而调用需要使用者主动调用的,
   * 当使用者需要执行的代码段执行成功时,使用者需要调用resolve函数,
   * 告诉Promise代码已经执行成功,并把执行结果传递给resolve函数,
   * 因此resolve函数里需要(改变Promise状态+存储结果),
   * 因此Promise需要2个属性PromiseState和PromiseResult用来保存数据
   */
  constructor(executor){

    function resolve(value){
      this.#PromiseState = FULFILLED
      this.#PromiseResult = value
    }

    function reject(reason){
      this.#PromiseState = REJECTED
      this.#PromiseResult = reason
    }

    executor(resolve, reject)
  }
}
第5步,resolve和reject需要一点点限制

// 定义Promise的3种状态
const PENDING = "pending"
const FULFILLED = "fulfilled"
const REJECTED = "rejected"

class MyPromise {

  // 初始状态为pending
  #PromiseState = PENDING
  #PromiseResult = undefined

  /**
   * 1,由于Promise是一个构造函数,所以需要实现constructor函数
   * 2,constructor函数接受一个回调函数executor,并且是同步执行的
   * 3,executor函数需要2个参数,
   * 一个是执行成功的resolve参数,
   * 一个是执行失败的reject参数,
   * 这2个参数都是函数,由于是在构造函数里执行的executor函数,
   * 所以resolve和reject这2个函数参数需要在这里定义,并传递给executor函数执行
   * 4,resolve和reject函数是Promise提供的,而调用需要使用者主动调用的,
   * 当使用者需要执行的代码段执行成功时,使用者需要调用resolve函数,
   * 告诉Promise代码已经执行成功,并把执行结果传递给resolve函数,
   * 因此resolve函数里需要(改变Promise状态+存储结果),
   * 因此Promise需要2个属性PromiseState和PromiseResult用来保存数据
   * 
   * 5,由于Promise的状态只能从pending变为fulfilled,
   * 或者从pending变为rejected,因此resolve和reject函数中需要加上限制,如下
   */
  constructor(executor){

    function resolve(value){
      if(this.#PromiseState !== PENDING) return // 第5点的限制
      this.#PromiseState = FULFILLED
      this.#PromiseResult = value
    }

    function reject(reason){
      if(this.#PromiseState !== PENDING) return // 第5点的限制
      this.#PromiseState = REJECTED
      this.#PromiseResult = reason
    }

    executor(resolve, reject)
  }
}


简单优化下代码

resolve和reject代码相似,抽离

// 定义Promise的3种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  // 初始状态为pending
  #PromiseState = PENDING
  #PromiseResult = undefined

  /**
   * 1,由于Promise是一个构造函数,所以需要实现constructor函数
   * 2,constructor函数接受一个回调函数executor,并且是同步执行的
   * 3,executor函数需要2个参数,
   * 一个是执行成功的resolve参数,
   * 一个是执行失败的reject参数,
   * 这2个参数都是函数,由于是在构造函数里执行的executor函数,
   * 所以resolve和reject这2个函数参数需要在这里定义,并传递给executor函数执行
   * 4,resolve和reject函数是Promise提供的,而调用需要使用者主动调用的,
   * 当使用者需要执行的代码段执行成功时,使用者需要调用resolve函数,
   * 告诉Promise代码已经执行成功,并把执行结果传递给resolve函数,
   * 因此resolve函数里需要(改变Promise状态+存储结果),
   * 因此Promise需要2个属性PromiseState和PromiseResult用来保存数据
   *
   * 5,由于Promise的状态只能从pending变为fulfilled,
   * 或者从pending变为rejected,因此resolve和reject函数中需要加上限制,如下
   */
  constructor(executor) {
    function resolve(value) {
      this.#changeState(FULFILLED, value)
    }

    function reject(reason) {
      this.#changeState(REJECTED, reason)
    }

    executor(resolve, reject)
  }

  #changeState(state, result) {
    if (this.#PromiseState !== PENDING) return // 第5点的限制
    this.#PromiseState = state
    this.#PromiseResult = result
  }
}
第6步,实现then方法
// 定义Promise的3种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  // 初始状态为pending
  #PromiseState = PENDING
  #PromiseResult = undefined
  #handlers = []

  /**
   * 1,由于Promise是一个构造函数,所以需要实现constructor函数
   * 2,constructor函数接受一个回调函数executor,并且是同步执行的
   * 3,executor函数需要2个参数,
   * 一个是执行成功的resolve参数,
   * 一个是执行失败的reject参数,
   * 这2个参数都是函数,由于是在构造函数里执行的executor函数,
   * 所以resolve和reject这2个函数参数需要在这里定义,并传递给executor函数执行
   * 4,resolve和reject函数是Promise提供的,而调用需要使用者主动调用的,
   * 当使用者需要执行的代码段执行成功时,使用者需要调用resolve函数,
   * 告诉Promise代码已经执行成功,并把执行结果传递给resolve函数,
   * 因此resolve函数里需要(改变Promise状态+存储结果),
   * 因此Promise需要2个属性PromiseState和PromiseResult用来保存数据
   *
   * 5,由于Promise的状态只能从pending变为fulfilled,
   * 或者从pending变为rejected,因此resolve和reject函数中需要加上限制,如下
   *
   * 6,实现then方法
   * then方法是Promise的实例方法,
   * then方法的返回值是Promise,因此直接写 return new MyPromise
   * 并且接受2个函数参数,onFulfilled和onRejected,
   * 这2个函数参数就是回调函数,当用户的代码块执行成功或失败会被调用
   * 调用onFulfilled还是onRejected,需要判断状态PromiseState
   * 调用的时候需要把resolve函数执行保存的结果传递到参数中
   *
   * 如果代码是异步执行的,PromiseState是PENDING的话
   * 就需要当用户主动resolve或reject的时候执行,代码要走到resolve或reject函数中,
   * resolve或reject函数需要拿到onFulfilled和onRejected函数参数,
   * 因此需要把onFulfilled和onRejected保存起来,handlers
   * 保存成功后,进入resolve或reject函数去调用,代码写到changeState中吧
   *
   * 那么then返回的Promise的resolve, reject函数参数什么时候执行,并且参数又是什么
   * 其实就是onFulfilled和onRejected执行后执行,参数是onFulfilled和onRejected的执行结果
   *
   */
  constructor(executor) {
    let resolve = (value) => {
      this.#changeState(FULFILLED, value)
    }

    let reject = (reason) => {
      this.#changeState(REJECTED, reason)
    }

    executor(resolve, reject)
  }

  #changeState(state, result) {
    if (this.#PromiseState !== PENDING) return // 第5点的限制
    this.#PromiseState = state
    this.#PromiseResult = result

    this.#execCallback()
  }
  #execCallback() {
    if (this.#PromiseState === PENDING) return

    let callback = this.#PromiseState == FULFILLED ? 'onFulfilled' : 'onRejected'
    while (this.#handlers.length) {
      let handler = this.#handlers.shift()

      // 无论第一个then是否成功还是失败,都走第二个then的成功,
      // 什么时候走第二个then的失败呢,try...catch
      try {
        let result = handler[callback](this.#PromiseResult)
        handler.resolve(result)
      } catch (error) {
        handler.reject(error)
      }
    }
  }

  // onFulfilled, onRejected什么时候执行
  // resolve, reject什么时候执行
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this.#handlers.push({
        onFulfilled,
        onRejected,
        resolve,
        reject,
      })

      this.#execCallback()
    })
  }
}

终版
  • executor必须为函数
  • then的onFulfilled或onRejected为null时,直接到下一个then
  • Promise.then里面的代码是异步执行的,把runThenCode放到微任务执行,
  • 微任务看这里:juejin.cn/editor/draf…
// 定义Promise的3种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

function isFun(fn) {
  return typeof fn === 'function'
}

class MyPromise {
  // 初始状态为pending
  #PromiseState = PENDING
  #PromiseResult = undefined
  #handlers = []

  /**
   * 1,由于Promise是一个构造函数,所以需要实现constructor函数
   * 2,constructor函数接受一个回调函数executor,并且是同步执行的
   * 3,executor函数需要2个参数,
   * 一个是执行成功的resolve参数,
   * 一个是执行失败的reject参数,
   * 这2个参数都是函数,由于是在构造函数里执行的executor函数,
   * 所以resolve和reject这2个函数参数需要在这里定义,并传递给executor函数执行
   * 4,resolve和reject函数是Promise提供的,而调用需要使用者主动调用的,
   * 当使用者需要执行的代码段执行成功时,使用者需要调用resolve函数,
   * 告诉Promise代码已经执行成功,并把执行结果传递给resolve函数,
   * 因此resolve函数里需要(改变Promise状态+存储结果),
   * 因此Promise需要2个属性PromiseState和PromiseResult用来保存数据
   *
   * 5,由于Promise的状态只能从pending变为fulfilled,
   * 或者从pending变为rejected,因此resolve和reject函数中需要加上限制,如下
   *
   * 6,实现then方法
   * then方法是Promise的实例方法,
   * then方法的返回值是Promise,因此直接写 return new MyPromise
   * 并且接受2个函数参数,onFulfilled和onRejected,
   * 这2个函数参数就是回调函数,当用户的代码块执行成功或失败会被调用
   * 调用onFulfilled还是onRejected,需要判断状态PromiseState
   * 调用的时候需要把resolve函数执行保存的结果传递到参数中
   *
   * 如果代码是异步执行的,PromiseState是PENDING的话
   * 就需要当用户主动resolve或reject的时候执行,代码要走到resolve或reject函数中,
   * resolve或reject函数需要拿到onFulfilled和onRejected函数参数,
   * 因此需要把onFulfilled和onRejected保存起来,handlers
   * 保存成功后,进入resolve或reject函数去调用,代码写到changeState中吧
   *
   * 那么then返回的Promise的resolve, reject函数参数什么时候执行,并且参数又是什么
   * 其实就是onFulfilled和onRejected执行后执行,参数是onFulfilled和onRejected的执行结果
   *
   */
  constructor(executor) {
    if (!isFun(executor)) {
      throw TypeError('MyPromise resolver undefined is not a function')
    }

    let resolve = (value) => {
      this.#changeState(FULFILLED, value)
    }

    let reject = (reason) => {
      this.#changeState(REJECTED, reason)
    }

    executor(resolve, reject)
  }

  #changeState(state, result) {
    if (this.#PromiseState !== PENDING) return // 第5点的限制
    this.#PromiseState = state
    this.#PromiseResult = result

    this.#execCallback()
  }
  #execCallback() {
    if (this.#PromiseState === PENDING) return

    while (this.#handlers.length) {
      let {onFulfilled, onRejected, resolve,reject} = this.#handlers.shift()

      // 无论第一个then是否成功还是失败,都走第二个then的成功,
      // 什么时候走第二个then的失败呢,try...catch
      try {
        if (this.#PromiseState === FULFILLED) {

          this.#runThenCode(onFulfilled,resolve,reject)

          // if (!isFun(onFulfilled)) {
          //   resolve(this.#PromiseResult)
          // } 
        } else {
          this.#runThenCode(onRejected,resolve,reject)

          // if (!isFun(onRejected)) {
          //   reject(this.#PromiseResult)
          // } 
        }
      } catch (error) {
        reject(error)
      }
    }
  }

  #runThenCode(callback, resolve,reject){
    // 如果是函数,正常执行
    if(isFun(callback)){
      let result = callback(this.#PromiseResult)
      resolve(result)
    }else if(this.#PromiseState === FULFILLED){ // 如果不是函数,但是执行成功,直接到下一个then的onFulfilled
      resolve(this.#PromiseResult)
    }else{ // 如果不是函数,并且执行失败,直接到下一个then的onRejected
      reject(this.#PromiseResult)
    }
  }

  // onFulfilled, onRejected什么时候执行
  // resolve, reject什么时候执行
  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this.#handlers.push({
        onFulfilled,
        onRejected,
        resolve,
        reject,
      })

      this.#execCallback()
    })
  }
}