手写Promise思维逻辑

思维流程

  1. 在使用promise时, 需要通过new关键字去new一个promise对象,由此可见, promise其实是一个class类
  2. 在执行这个类时,需要传递一个回调函数(执行器executor), 执行器会立即执行
  3. promise当中有三种状态 pending fulfilled rejected 等待 成功 失败,并且状态确定后就不可改变
    • pending ==> fulfilled
    • pending ==> rejected
  4. resolve(将状态变为fulfilled) 和 reject是用来更改状态的(将状态变为rejected)
  5. 传给resolve的值就是执行成功后的值, 传给reject的值就是执行失败的原因
  6. promise可以调用then方法, 在执行then中的方法时判断promise的状态, 如果状态是fulfilled,则需要调用成功回调, 如果状态是rejected,则需要调用失败回调, then方法是原型对象上的一个方法
  7. then成功回调有一个参数表示成功的值, 失败回调有一个参数表示失败的原因
    • (1~7具体实现请参考: promise基本逻辑实现)
  8. 因为创建promise实例对象后, 传递的执行器会立即执行, 当执行器执行时,如果发现执行器中有异步代码, 这个时候,主线程中的代码是不会等待异步代码执行完毕再执行,而是会立即执行,
    所以then方法立刻执行, 而then方法中去判断了promise的状态, 由于当前这个promise并没有执行resolve或reject, 所以当前promise的状态一定是pending,
    而到现在为止,Mypromise的then方法当中没有判断pending的状态, 那么在添加promise的异步处理时,在then中去判断pending - (具体实现请参考: promise异步处理逻辑实现)
  9. promise对象下的then方法是可以多次被调用的, 当then方法被多次调用的时候, 每一个then方法中传递的回调函数都是要被多次执行的,而这种情况也要分两种情况: 回调是同步代码, 回调是异步代码
    • 同步函数: 到此为止已不需要为同步代码在进行请他处理
    • 异步代码: 每一个then方法中的每一个回调函数都要把它储存起来,当状态变为成功或失败时再去依次调用
    • (具体实现请参考: 实现then方法多次调用)
  10. then方法是可以被链式调用的, 后面then方法的回调函数拿到的值是上一个then方法的回调函数的返回值
    • 如果要实现then方法的链式调用, 那么每一个then方法都应该<font color=’#FF0000’返回一个promise对象
    • 如何把上一个then方法回调函数的返回值传递给下一个then方法的回调函数
    • 返回的是一个普通值
    • 返回的是一个promise对象, 查看这个promise对象所返回的结果, 再根据返回的结果,去调用resolve还是reject
    • (具体实现请参考: 实现then方法的链式调用)
  11. 在then方法中不可以返回当前then方法所返回的promise对象, 并捕捉promise执行中的异常
    • 在then方法中不可以返回当前then方法所返回的promise对象, 如果返回的话,会导致当前promise的循环调用
    • (具体实现请参考: promise链式调用识别自身并捕捉promise执行中的异常)
  12. then方法的两个参数成功和失败回调都是可选参数
  13. Promise.all方法
    • 用来解决异步并发问题, 允许我们通过异步代码调用的顺序得到异步代码执行的结果
    • 通过类.all的方法来调用, 所以all方法是一个静态方法
  14. promise.resolve
    • promise.resolve会将给定的值转换成promise对象
  15. promise.finally
    • 无论promise方法返回的是成功还是失败, finally中的回调函数都会被执行一次
    • 可以链式调用then方法拿到这个promise对象最终返回的结果
  16. promise.catch
    • 失败回调
    • (12~16具体实现请参考: 将then方法变为可选参数, promise.all, promise.resolve, promise.finally, promise.catch)

promise基本逻辑实现

  1. // 声明promise的状态
  2. const PENDING = 'pending'
  3. const FULFILLED = 'fulfilled'
  4. const REJECTED = 'rejected'
  5. class MyPromise {
  6. constructor (executor) {
  7. executor(this.resolve, this.reject) // 执行器立即执行
  8. }
  9. status = PENDING //promise的状态
  10. value = undefined; // 用来储存成功的值
  11. reason = undefined; //用来储存失败原因
  12. // 因为在执行器中调用resolve 或 reject时是直接调用的, 如果写普通的function函数,那么resolve和reject的this指向会是window或是undefined
  13. // 定义为箭头函数是为了让他们的this指向为promise的实例对象
  14. resolve = value => {//添加resolve属性用来改变状态
  15. if (this.status !== PENDING) return //判断状态是否更改过, 如果更改了,那么就不再向下执行, reject同理
  16. // 将状态更改为成功
  17. this.status = FULFILLED
  18. this.value = value //储存成功的值, 方便在then中取到
  19. }
  20. reject = reason => {//添加reject属性用来改变状态
  21. if (this.status !== PENDING) return
  22. // 将状态更改为失败
  23. this.status = REJECTED
  24. this.reason = reason//储存失败的值, 方便在then中取到
  25. }
  26. then (successCallBack, failCallBack) {
  27. if (this.status === FULFILLED) { //如果状态是fulfilled,则需要调用成功回调, 并传递成功的值
  28. successCallBack(this.value)
  29. } else if (this.status === REJECTED) { // 如果状态是rejected,则需要调用失败回调, 并传递失败的原因
  30. failCallBack(this.reason)
  31. }
  32. }
  33. }

promise异步处理逻辑实现

class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING
  value = undefined;
  reason = undefined;
  // 储存成功回调
  successCallBack = undefined
  // 储存失败回调
  failCallBack = undefined
  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    // 判断成功回调是否存在, 如果存在就调用并将成功的值传回去
    this.successCallBack instanceof Function && this.successCallBack(this.value)
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    // 判断失败回调是否存在, 如果存在就调用并将失败原因传回去
    this.failCallBack instanceof Function && this.failCallBack(this.reason)
  }
  then (successCallBack, failCallBack) {
    if (this.status === FULFILLED) {
      successCallBack(this.value)
    } else if (this.status === REJECTED) {
      failCallBack(this.reason)
    } else { //如果走到了else, 就说明该promise的状态是pending, 因为现在并不知道promise是成功还是失败,所以将successCallBack和failCallBack临时储存起来, 当异步代码执行时再去调用成功或失败回调
      this.successCallBack = successCallBack
      this.failCallBack = failCallBack
    }
  }
}

实现then方法多次调用

class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING
  value = undefined;
  reason = undefined;
  // 为了储存多个成功回调和失败回调, 因此successCallBack和failCallBack要为数组
  successCallBack = []
  failCallBack = []
  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    // while循环依次调用储存的成功回调
    while (this.successCallBack.length) this.successCallBack.shift()(this.value)
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    // while循环依次调用储存的失败回调
    while (this.successCallBack.length) this.successCallBack.shift()(this.reason)
  }
  then (successCallBack, failCallBack) {
    if (this.status === FULFILLED) {
      successCallBack(this.value)
    } else if (this.status === REJECTED) {
      failCallBack(this.reason)
    } else {
      // 将成功回调和失败回调储存起来
      if (successCallBack instanceof Function) this.successCallBack.push(successCallBack)
      if (failCallBack instanceof Function) this.failCallBack.push(failCallBack)
    }
  }
}

实现then方法的链式调用

class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING
  value = undefined;
  reason = undefined;
  successCallBack = []
  failCallBack = []
  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    while (this.successCallBack.length) this.successCallBack.shift()(this.value)
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while (this.successCallBack.length) this.successCallBack.shift()(this.reason)
  }
  then (successCallBack, failCallBack) {
    // 既然要返回一个promise对象, 那么就要创建一个promise对象
    let newPromise = new MyPromise((resolve, reject) => { //promise中执行器是立即执行的, 而之前then方法中的代码也需要立即执行,所以将这些代码放入执行器中
      // 想要将上一个then方法的返回值传递给下一个then方法, 而每一个then方法都会返回一个promise对象,而这个promise对象就是newPromise, 那么只要调用newPromise的resolve方法就可以把成功的值传递给下一个then方法
      if (this.status === FULFILLED) {
        let successInfo = successCallBack(this.value) //在这里调用了成功回调, 就可以在这里拿到这个成功回调的返回值
        resolvePromise(successInfo, resolve, reject)
      } else if (this.status === REJECTED) {
        failCallBack(this.reason) //在这里调用了失败回调, 就可以在这里拿到这个失败回调的失败原因
      } else {
        if (successCallBack instanceof Function) this.successCallBack.push(successCallBack)
        if (failCallBack instanceof Function) this.failCallBack.push(failCallBack)
      }
    })
    return newPromise
  }
}
function resolvePromise (c, resolve, reject) {
  // 判断是否为MyPromise的实例对象, 如果不是,那它就是一个普通值
  if (c instanceof MyPromise) {
    c.then(resolve, reject)
  } else {
    // 普通值
    resolve(c)
  }
}

promise链式调用识别自身并捕捉promise执行中的异常

class MyPromise {
  constructor (executor) {
    executor(this.resolve, this.reject)
  }
  status = PENDING
  value = undefined;
  reason = undefined;
  successCallBack = []
  failCallBack = []
  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    while (this.successCallBack.length) this.successCallBack.shift()(this.value)
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while (this.successCallBack.length) this.successCallBack.shift()(this.reason)
  }
  then (successCallBack, failCallBack) {
    let newPromise = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
         setTimeout(() => { // 因为单单的resolvePromise是同步代码, 在resolvePromise执行时, newPromise正在创建实例中, 是获取不到newPromise的,
                                   // 所以用setTimeOut将newPromise变为异步代码, 在newPromise市里完成后就可以获取到newPromise
           let successInfo = successCallBack(this.value)
           resolvePromise(newPromise, successInfo, resolve, reject) // 将newPromise作为参数传递给resolvePromise方法, 用来判断then方法中是否返回了自己本身的promise
         }, 0)
      } else if (this.status === REJECTED) {
        failCallBack(this.reason)
      } else {
        if (successCallBack instanceof Function) this.successCallBack.push(successCallBack)
        if (failCallBack instanceof Function) this.failCallBack.push(failCallBack)
      }
    })
    return newPromise
  }
}
function resolvePromise (newPromise, c, resolve, reject) {
  if (newPromise === c) { //判断promise是否返回了自己, 并抛出异常
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (c instanceof MyPromise) {
    c.then(resolve, reject)
  } else {
    resolve(c)
  }
}

将then方法变为可选参数, promise.all, promise.finally , promise.catch

class MyPromise {
  constructor (executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }
  status = PENDING
  value = undefined;
  reason = undefined;
  successCallBack = []
  failCallBack = []
  resolve = value => {
    if (this.status !== PENDING) return
    this.status = FULFILLED
    this.value = value
    while (this.successCallBack.length) this.successCallBack.shift()()
  }
  reject = reason => {
    if (this.status !== PENDING) return
    this.status = REJECTED
    this.reason = reason
    while (this.failCallBack.length) this.failCallBack.shift()()
  }
  then (successCallBack, failCallBack) {
    successCallBack = successCallBack instanceof Function ? successCallBack : value => value //判断successCallBack是否为true 如果为true 则执行successCallBack, 否则将返回值再传递给后面的then方法
    failCallBack = failCallBack instanceof Function ? failCallBack : reason => { throw reason } //判断failCallBack是否为true 如果为true 则执行failCallBack, 否则将失败原因再传递给后面的then方法
    let newPromise = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
         setTimeout(() => {
           try {
             let successInfo = successCallBack(this.value)
             resolvePromise(newPromise, successInfo, resolve, reject)
           }catch (e) {
             this.reject(e)
           }
         }, 0)
      } else if (this.status === REJECTED) {
        setTimeout(() => {
          try {
            let failInfo = failCallBack(this.reason)
            resolvePromise(newPromise, failInfo, resolve, reject)
          }catch (e) {
            this.reject(e)
          }
        }, 0)
      } else {
        if (successCallBack instanceof Function) this.successCallBack.push(() => {
          setTimeout(() => {
            try {
              let successInfo = successCallBack(this.value)
              resolvePromise(newPromise, successInfo, resolve, reject)
            }catch (e) {
              this.reject(e)
            }
          }, 0)
        }) //
        if (failCallBack instanceof Function) this.failCallBack.push(() => {
          setTimeout(() => {
            try {
              let failInfo = failCallBack(this.reason)
              resolvePromise(newPromise, failInfo, resolve, reject)
            }catch (e) {
              this.reject(e)
            }
          }, 0)
        })
      }
    })
    return newPromise
  }
  finally (callback) {
    if (callback instanceof Function) {
      // 调用then方法获取当前promise的状态
      return this.then(value => { // 因为finally是链式调用, 所以需要返回一个promise对象,而then方法本身就会返回一个promise对象, 所以直接 return then
        return  MyPromise.resolve(callback()).then(() => value)
      }, reason => {
        return  MyPromise.resolve(callback()).then(() => {throw reason})
      })
    }
  }
  catch (failCallBack) {
    return this.then(undefined, failCallBack) // 将成功回调置为undefined, 直接调用失败回调
  }
  static all (array) {// 接受一个数组作为参数
    // all 方法返回的是一个promise对象, 那么必定要返回一个promise对象
    let resultArr = [] //结果数组
    let index = 0
    return new MyPromise((resolve, reject) => {
      // 循环array, 判断array中的每个值是普通值还是promise对象, 如果是普通值就直接放到结果数组当中, 如果是promise对象,
      // 就先去执行promise对象, 然后再把promise对象的结果放到结果数组当中
      function addData (key, value) {
        resultArr[key] = value
        index++
        if (index = array.length) {// 因为会有array中可能会有异步代码, 所以判断index是否等于array的长度, 如果相等, 就证明array中的代码已经执行完毕,可以调用resolve方法
          resolve(resultArr)
        }
      }
      for (let i = 0; i < array.length; i++) {
        let current = array[i]
        if (current instanceof MyPromise) { //判断是否为promise对象, 如果不是, 那就是普通值
          current.then(value => addData(i, value), reason => reject(reason))
        } else {
          addData(i, current)
        }
      }
    })
  }
  static resolve (value) {
    if (value instanceof MyPromise) return value // 判断是否为promise对象, 如果是则直接返回, 如果不是, 就要创建一个promise对象, 通过resolve返回value
    return new MyPromise(resolve => resolve(value))
  }
}
function resolvePromise (newPromise, c, resolve, reject) {
  if (newPromise === c) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (c instanceof MyPromise) {
    c.then(resolve, reject)
  } else {
    resolve(c)
  }
}

到这一步, 手写promise已完成