promise实现详细解析

229 阅读3分钟
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

/**
 *  流程:
*   new Promise((resolve, reject) => {
    resolve(1)
    reject(2)
    resolve(new Promise((resolve) => resolve(123)))
}).then((r) => console.log(r, 123456), (e) => console.log(e, 123))
 *   new Promise() 注册构造函数,初始化状态PENDING
     Promise中注册executor函数
 * 
 */


function Promise(executor) {
  const self = this
  self.status = PENDING
  self.onFulfilled = []
  self.onRejected = []

  function resolve(value) {
    if (self.status === PENDING) {
      self.status = FULFILLED
      self.value = value //为什么value要加到this(self)里? 因为在promise.then里面要return value 
      // self.onFulfilled.forEach((fn)=>fn()) //为什么不传value?
      self.onFulfilled.forEach((fn) => fn())
    }

  }

  function reject(value) {
    if (self.status === PENDING) {
      self.status = REJECTED
      self.value = value
      self.onRejected.forEach(fn => fn())
    }
  }
  try {
    executor(resolve, reject)
    /**
     * promise 中传入回调函数就是executor,executor中传入两个函数 分别是resolve,reject
     */
  } catch (e) {
    reject(e)
  }
}
Promise.prototype.then = function (onFulfilled, onRejected) {
  typeof onFulfilled === 'function' ? onFulfilled : value => value //判断onFulfilled是不是函数,不是函数则创建一个函数返回值是传入的值
  typeof onRejected === 'function' ? onRejected : value => value //判断onRejected是不是函数,不是函数则创建一个函数返回值是传入的值
  const self = this
  //then 会返回一个promise对象
  let promise2 = new Promise((resolve, reject) => {
    //异步执行,讲任务加入任务队列,定时器到时间之后把注册的回调加到任务队列的队尾
    if (self.status === FULFILLED) {
      //第三步,当resolve或者reject后从pending里面注册的函数中来到了这里
      setTimeout(() => {
        try {
          const x = onFulfilled(self.value) //用户传入then的回调函数的结果,如果没有return x就是undefined
          resolvePromise(promise2, x, resolve, reject) //即将开始第四步
        } catch (error) {
          reject(error) //报错就进入这里就结束了
        }
      })
    } else if (self.status === REJECTED) {
      setTimeout(() => {
        try {
          const x = reject(self.value)
          resolvePromise(promise2, x, resolve, reject)
        } catch (error) {
          reject(error)
        }
      })

    } else if (self.status === PENDING) {
      /** 这里的第几部都是通常情况下,例外情况下的情况可以自己再理解
       * 第0步 pending 状态会将成功和失败的函数都注册一下到promise的内部数组中,
       * 一般就是先注册了之后再执行fulfilled或者rejected
       * self.onFulfilled.forEach((fn) => fn()) 在resove中会把这个成功或者失败的函数循环遍历一次
       */
      self.onFulfilled.push(() => {
        setTimeout(() => {
          try {
            const x = onFulfilled(self.value)
            resolvePromise(promise2, x, resolve, reject) //到了resolve的时候会重新进入函数 第一步
          } catch (error) {
            reject(error)
          }
        });
      })
      self.onRejected.push(() => {
        setTimeout(() => {
          try {
            const x = onRejected(self.value)
            resolvePromise(promise2, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        });
      })
    }
  })
  return promise2
}

function resolvePromise(promise2, x, resolve, reject) {
  if (promise2 === x) { //第四步,判断x是否为let a = new Promise(()=>{resolve(a)})的情况,我猜会变成无限pending,要防止
    reject(new TypeError('Chaining cycle'));
  }
  if (x && typeof x === 'object' || typeof x === 'function') {
    //判断传入的x是不是存在对象或者函数,如果是的话就看看是不是promise promise就有then方法,并且要等待作为promise的x的执行完毕
    let used; // 之所以定义used 是因为在一个函数里面可能出现多个resolve reject的组合,只能执行一次,used在这里是闭包,在call注册的两个函数中只能执行一个,剩下被注册的就会被return了.
    try {
      let then = x.then
      if (typeof then === 'function') {
        //如果x是promise并且跟着还有then的话就要递归等待所有then结束
        then.call(x, (y) => {
          if (used) return;
          used = true
          resolvePromise(promise2, y, resolve, reject) //重新进入第三步,循环调用直到x不为一个对象然后就到下面的resolve,这里为第五步
        }, (r) => {
          if (used) return; //同样这里和上面一样是第五步 是可能性的分支
          used = true
          reject(r)
        })
      } else { //也是第五步,x不是promise对象 不带有then就到这里
        if (used) return;
        used = true;
        resolve(x)
      }
    } catch (error) { //上面报错就到这里 也是第五步
      if (used) return;
      used = true;
      reject(error)
    }
  } else { //当x不为对象,通常是常量 比如resolve(2) 或者 then(()=>2) x就为2  
    resolve(x) //
  }
}
new Promise((resolve, reject) => {
  resolve(1)
  reject(2)
  resolve(new Promise((resolve) => resolve(123)))
}).then((r) => console.log(r, 123456), (e) => console.log(e, 123))