Skip to content
大纲

手写promise

js
/*
 * @Author: maps131_liaoxing
 * @Date: 2021-06-11 15:58:48
 * @LastEditors  : maps131_liaoxing
 * @LastEditTime : 2021-06-29 00:12:53
 * @Description: 手写promise
 * promise规则
 *  0. 自身有reslove、reject、then、catch、finally、all、race方法
 *  1. 可以链式调用then、catch、finally,且catch、finally不阻断链式调用
 *  3. resolve后执行then的第一个函数参数,然后进行链式调用
 *  4. reject后执行then的第二函数参数,如果没则执行catch调用,如果没catch调用,则报错 Uncaught (in promise) param,然后进行链式调用
 *  5. 链式调用返回值可以是promise对象,后面的链式调用都属于新promise对象
 *  6. 同步执行和异步执行的结果都一样
 *  7. resolve、reject的参数和链式调用的返回值,作为下一个链式调用的参数
 *  8. 同一promise,catch执行一次
 *  9. all方法需要等所有promise执行完毕出发,包括其链式调用,如果链式调用不返回值,all接收的值为undefined
 *  10. race方法返回最快执行完毕返回值,包括其链式调用,如果链式调用不返回值,race接收的值为undefined,不阻断较慢promise执行
 */

class $Promise{
  /**
   * @description: 模拟promise上面的11条规则,我这里主干逻辑是保证所有的链式调用,遇到所有pendding状态的promise,都将其添加进等待任务,等状态改变后循环触发
   * @param { Function } callBack
   * @param { String } name
   * @return {*}
   */  
  constructor (callBack, name) {
    if (typeof callBack !== 'function') {
      throw new Error('$Promise resolver ' + callBack +' is not a function')
    }
    this.name = name
    this.status = 'pedding' // 状态
    this.resParam = null // res与链式传递的值
    this.rejParam = null // rej的值
    this.waitTask = [] // 被异步阻断的任务
    callBack(this.resolve.bind(this), this.reject.bind(this))
  }
  resolve (param) {
    this.status = 'resolved'
    this.resParam = param
    /* 触发等待的任务 */
    this.oprateTask()
  }
  reject (param) {
    this.status = 'rejected'
    this.rejParam = param
    /* 如果一直处于rejected状态说明没catch和then第二参,报个错 */
    setTimeout(() => {
      if (this.status === 'rejected') {
        console.error('Uncaught (in $Promise)', this.rejParam)
      }
    })
    /* 触发等待的任务 */
    this.oprateTask()
  }
  then (next, rejNext) {
    if (!next) return this
    /* 返回值是$Promise对象,将后面的 */
    if (this.resParam instanceof $Promise) {
      let that = this.resParam
      return this.oprateThen(that, next, rejNext)
    }
    /* 返回值不是$Promise对象 */
    return this.oprateThen(this, next, rejNext)
  }
  catch (next) {
    /* 返回值是$Promise对象 */
    if (this.resParam instanceof $Promise) {
      let that = this.resParam
      return this.oprateCach(that, next)
    }
    /* 返回值不是$Promise对象 */
    return this.oprateCach(this, next)
  }
  finally (next) {
    if (this.resParam instanceof $Promise) {
      let that = this.resParam
      return this.oprateFina(that, next)
    }
    /* 返回值不是$Promise对象 */
    return this.oprateFina(this, next)
  }
  oprateTask () {
    /* 如果没有等待任务就直接调出 */
    if (!this.waitTask.length) return
    /* 循环调用等待任务,根据类型用方法调用 */
    this.waitTask.forEach(item => {
      if (item.res) {
        this.then(item.res, item.rej)
      } else if(item.fina) {
        this.finally(item.fina)
      } else {
        this.catch(item.catch)
      }
    })
  }
  oprateThen (that, next, rejNext) {
    /* 等待状态,将链式调用加进等待任务,待状态改变循环调用 */
    if (that.status === 'pedding') {
      that.waitTask.push({res: next, rej: rejNext || null, catch: null, fina: null})
    }
    /* 解决状态直接执行then,并将返回值赋给resParam,然后当作下一链式调用的参数 */
    if (that.status === 'resolved') {
      that.resParam = next(that.resParam)
    }
    /* 有第二参就执行,并改状态,以便后面的链式,没就直接返回that,调用下一个链式 */
    if (that.status === 'rejected') {
      if (!rejNext) return that

      that.rejParam = rejNext(that.rejParam)

      that.resParam = that.rejParam
      that.status = 'resolved'
    }
    /* 返回that,才有链式的指向 */
    return that
  }
  oprateCach (that, next) {
    if (that.status === 'pedding') {
      that.waitTask.push({res: null, rej: null, catch: next, fina: null})
    }
    /* 只有rejected状态才能触发,将返回值指向resParam,然后修改状态,以便下一链式调用 */
    if (that.status !== 'rejected') return that
    that.rejParam = next(that.rejParam)

    that.resParam = that.rejParam
    that.status = 'resolved'
    /* 返回that,才有链式的指向 */
    return that
  }
  oprateFina (that, next) {
    if (that.status === 'pedding') {
      that.waitTask.push({res: null, rej: null, catch: null, fina: next})
      return that
    }
    /* finally直接触发,没参数没返回 */
    next()
    /* 返回that,才有链式的指向 */
    return that
  }
}

$Promise.all = (promiseList) => {
  let count = promiseList.length // 用来判断有没有全部执行完毕
  let resData = [] // 存储返回值
  resData.length = count // 赋值empty空值
  /* 向返回值添加值,并-1,相当于完毕一个执行,等于0时res返回值,all结束 */
  const judge = (index, result, res) => {
    resData[index] = result
    count--
    if (!count) res(resData)
  }
  /* 返回各$Promise,以便then */
  return new $Promise((res, rej) => {
    /* 循环调用 */
    promiseList.forEach((item, index) => {
      item.then(data => {
        judge(index, data, res)
      }) 
    })
  })
}

$Promise.race = (promiseList) => {
  let resData = null // 存储最快执行完毕的返回值
  /* 有返回值了就不再触发res */
  const judge = (data, res) => {
    if (resData) return
    resData = data
    res(resData)
  }
  return new $Promise((res, rej) => {
    /* 循环调用 */
    for (let item of promiseList) {
      item.then(data => {
        judge(data, res)
      })
    }
  })
}

Released under the MIT License.