手写promise的几个核心概念

455 阅读3分钟

核心概念和流程

promise有几个重要的概念,只要弄明白这几点,基本上就可以实现大致的框架了

  • promise中有三种状态,pendingfulfilledrejected
  • 每一个promise一旦resolve,他的状态马上变成fulfilled,再执行自己的onResolve函数后,resolve下一个promise,依次类推
  • then接收onResolveonReject作为参数,如果这两个函数返回值为promise,则要等待这个promise,如果返回值不是promise,则将这个返回值传递给下一个promise
  • then会返回一个promise对象

测试函数

首先写一些主要的测试代码

<!-- 异步 -->
new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log('executor')
    resolve(1)
  }, 1000)
})
.then(value => {
  console.log('then1', value)
  return 2
})
.then(value => {
  console.log('then2', value)
})
<!-- 同步 -->
new Promise((resolve, reject) => {
  console.log('executor')
  resolve(1)
})
.then(value => {
  console.log('then1', value)
  return 2
})
.then(value => {
  console.log('then2', value)
})
<!-- 同步 异步 嵌套promise -->
new Promise((resolve, reject) => {
  console.log('外部promise')
  resolve(1)
})
.then(value => {
  console.log('外部then1', value)
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log('内部promise')
      resolve(2)
    }, 1000)
  })
  .then(value => {
    console.log('内部then1', value);
    return 3
  })
  .then(value => {
    console.log('内部then2', value);
    return 4
  })
})
.then(value => {
  console.log('外部then2', value);
})

实现executor

第一步肯定是实现new Promise(executor)的写法,调用promise的构造函数,传入一个参数为resolvereject的函数,并立即执行

constructor(executor) {
  this.state = "pending";
  this.value = undefined;
  this.reason = undefined;
  this.resolveCallbacks = []
  this.nextPromise = undefined
  if (executor && typeof executor === "function") {
    executor(this.resolve.bind(this), this.reject.bind(this));
  }
}

实现resolve

  • resolve接受一个value,并且改变promise的状态
  • resolve改变状态后,执行自己的onResolve回调
  • 执行下一个promiseresolve,其中还要判断onResolve返回的是否为promise对象,是的话要等待这个promise
resolve(value) {
  if (this.state === "pending") {
    this.state = "fulfilled"
    this.value = value
    if (this.resolveCallbacks.length) {
      // 调用then中注册的onResolve回调
      while(this.resolveCallbacks.length) {
        const onResolve = this.resolveCallbacks.pop()
        const result = onResolve(value)
        if (result instance of Promise) {
          // 如果是promise对象,调用这个promise的then
          result.then(v => {
            this.nextPromise && this.nextPromise.resolve(value)
          })
        } else {
          this.nextPromise && this.nextPromise.resolve(value)
        }
      }
    } else {
      // 没有的话就执行下一个promise的回调
      this.nextPromise && this.nextPromise.resolve(value)
    }
    
  }
}

实现then

  • 如果状态已经是fulfilled,这个时候就马上执行onResolve回调
  • 如果状态是pending,这个时候要把onResolve存起来
  • then一直会返回一个promise对象
then(onResolve, onReject) {
  let promise = new Promise()
  if (this.state === "fulfilled") {
    // 如果onResolve返回的不是一个promise对象,就返回一个马上resolve的promise
    // 如果onResolve返回的是promise,就在该promise对象的then里面resolve
    promise = new Promise((resolve, reject) => {
      if (onResolve && typeof onResolve === "function") {
        const result = onResolve(this.value)
        if (result instanceof Promise) {
          result.then(value => {
            resolve(value)
          })
        } else {
          resolve(result)
        }
      } else {
        resolve(this.value)
      }
    })
  } else if (this.state === "pending") {
    if (onResolve && typeof onResolve === "function") {
      this.resolveCallbacks.push(onResolve)
    }
  }
  this.nextPromise = promise
  return promise
}

待完成

  • thencatch的回调必须放到微任务队列执行的(window.queueMicrotask或者proess.nextTick),注意不是setTimeout
  • 添加try catchreject,注意catchreject都是异常捕获,并且发生异常的时候catchreject会按照声明顺序,只执行一个最先声明的一个
  • 添加静态方法resolvereject

其他

  • 完整的代码可以参考下面的链接
  • github.com/Leonewu/dai…
  • 写完之后对eventloopmicroTaskmacroTaskpromise的执行机制的理解都清晰很多了
  • 写的比较简洁,欢迎补充^_^

参考