私人笔记之手写Promise

186 阅读2分钟
import { isFunction } from "util";

const PANDING = 'panding'
const RESOLVE = 'resolve'
const REJECT = 'reject'

function MyPromise(dosth) {
  // 状态标识
  let status = PANDING
  // 用来存储回调方法,因为支持链式then,所以用数组存储多个回调
  let resolveCallback = []
  let rejectCallback = []
  this.value = null

  // 思路:一次次迭代,逐步完善
  /**
   * 1、实现基本功能:
   *   * then存储回调
   *   * reslove和reject执行回调
   *   * 执行异步操作
   * 2、控制状态
   * 3、then链式调用
   * 4、回调在执行栈执行完之后才执行
   * 5、 串行promise 当前promise达到resolve状态后才开始下一个promise
   */

  // 实现resolve和reject
  function resolve (res) {
    // 异步函数需要在执行栈主流程执行完之后才可以开始执行
    setTimeout(() => {
      // 只有状态为panding才可以改变状态
      if (status === PANDING ) {
        // 执行回调方法
        status = RESOLVE
        that.value = res
        resolveCallback.forEach(cb => {
          cb(that.value)
        })
      }
    }, 0);
  }

  function reject (err) {
    setTimeout(() => {
      if (status === PANDING) {
        status = REJECT
        that.value = err
        rejectCallback.forEach(cb => {
          cb(that.value)
        })
      }
    }, 0);
  }

  // 执行异步操作
  try{
    dosth()
  } catch(err) {
    reject(err)
  }
}

// 实现then方法
MyPromise.prototype.then = function (onResolve, onReject) {
  const that = this
  // 串行promise: 当前Promise执行完毕后执行下一个promise
  // 这里用resolve2 和reject2 表示该处两个方法属于下方新的myPromise,暂时称为promise2,方法中用到的变量也属于promise2
  let myPromise2 = new MyPromise((resolve2, reject2) => {

    /**
     *
     * @param {*} val value
     * @param {*} onR onReject or onResolve
     * @param {*} Re2 reject2 or resolve2
     */
    function doOnRe(val, onR, Re2) {
      // 把当前promise的回调返回值传给下一个promise
      var ret = isFunction(onR) && onR(val) || val
      // 如果ret是一个promise对象,那在这个promise得到结果才执行resolve2
      if (ret && typeof ret['then'] === 'function') {
        ret.then(function (val) {
          Re2(value)
        })
      } else {
        Re2(ret)
      }

    }

    /**
     * then 的功能
     * 1、存储回调函数
     */
    if (status === PANDING) {
      rejectCallback.push(doOnResolve)
      resolveCallback.push(doOnReject)
    } else if (status === RESOLVE) {
      doOnRe(that.value, onResolve, resolve2)
    } else {
      doOnRe(that.value, onReject, reject2)
    }
  })
  // 2、支持链式回调
  return myPromise2
}

// 实现all方法
// Promise.all 可以接收一个元素为 Promise 对象的数组作为参数,当这个数组里面所有的 Promise 对象都变为 resolve 时,该方法才会返回。
MyPromise.prototype.all = function(promiseArray) {
  if (!Array.isArray(promiseArray)) {
    throw new TypeError('You must pass an array to all.');
  }

  return new MyPromise((resolve, reject) => {
    let pNum = promiseArray.length
    let successNum = 0
    // 用来保存各个promise的回调结果
    let result = []
    for(let i = 0; i < pNum; i++) {
      promiseArray[i].then((res) => {
        successNum ++
        result.push(res)
        // 如果所有都已经成功了
        if (successNum === pNum) {
          resolve(result)
        }
      }, (err) => {
        reject(err)
        break;
      })
    }
  })
}

// 实现race
/**
 * const p = Promise.race([p1, p2, p3]);
  上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
 */
MyPromise.prototype.race = function(promiseArray) {
  if (!Array.isArray(promiseArray)) {
    throw new TypeError('You must pass an array to all.');
  }

  return new MyPromise((resolve, reject) => {
    let pNum = promiseArray.length
    for(let i = 0; i< pNum; i++) {
      promiseArray[i].then(res => {
        resolve(res)
        break;
      })
    }
  })
}