浅谈promise

227 阅读4分钟
遵循PromiseA+规范
  1. promise 是一个有 then 方法的对象或者函数,行为遵循本规范
  2. thenable 是一个有then 方法的对象或者函数
  3. value 是 promise 状态成功时的值,也就是 resolve 的参数,包括各种数据类型,也包括undefined / thenable 或者 promise
  4. reason 是 promise 状态失败时的值,也就是reject的参数,表示拒绝的原因
  5. exception 是使用 、throw 抛出的异常的值
Promise 应该有三个状态
  1. pending 状态
    • promise 的初始状态,可改变;一个promise 在resolve 和 reject 之前都处于这个状态;可以通过resolve 改为 fulfilled OR 通过 reject 改为 rejected;
  2. fulfilled 状态
    • 最终状态不可改变;一个promise 被resolve 后变成这个状态,必须有一个value 值
  3. rejected 状态
    • 最终状态不可改变;一个promise 被reject 后变成这个状态,必须有一个reason 值
Promise 应该有一个then方法
  • promise.then(onFulfilled, onRejected) tips: onFulfilled, onRejected 必须是函数,只能被调用一次(so 通过一个变量来控制,限制执行次数);在promise变成 fulfilled 时,应该调⽤ onFulfilled, 参数是value; 在promise变成 rejected 时,应该调⽤ onRejected, 参数是reason;在Promise 的状态为pending 的时候不应该被调用
  • onFulfilled, onRejected 应该是微任务,so 通过 queueMicrotask 来实现微任务的调用
  • then 方法应该返回一个Promise 如:promise2 = promise1.then( onFulfilled, onRejected)
  • promise 的状态变为 fulfilled 或者 rejected 的时候,所有的onFulfilled 或者 onRejected 都需要按照then的顺序执行,也就是按照注册的顺序执行,所以我们需要一个数组来存放这行状态函数
以下为手写的Promise
//定义promise 需要的三个状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";

class APromise {
  //需要三个参数,分别是fulfilled下的所有函数数组,rejected 下的所有函数数组,以及 一个状态
  FULFILLED_CALLBACK_LIST = [];
  REJECTED_CALLBACK_LIST = [];
  _status = PENDING;
  constructor(fn) {
    //初始化promise的状态为pending, 定义value 与 reason
    this.status = PENDING;
    this.value = null;
    this.reason = null;
    //promise 默认刚进入会执行一次函数,同步执行, 异常的时候reject 出去
    try {
      fn(this.resolve.bind(this), this.reject.bind(this))
    }catch (e) {
      this.reject(e)
    }
  }
  //通过 es6 的getter setter 监听状态值的变化
  get status() {
    return this._status
  }
  set status(newStatus) {
    this._status = newStatus;
    switch (newStatus) {
      case FULFILLED : {
        this.FULFILLED_CALLBACK_LIST.forEach(callback => callback(this.value));
        break;
      }
      case REJECTED: {
        this.REJECTED_CALLBACK_LIST.forEach(callback => callback(this.reason))
      }
    }
  }
  //resolve 修改状态为 fulfilled, 并且赋值 value
  resolve(value) {
    if(this.status === PENDING) {
      this.value = value;
      this.status = FULFILLED
    }
  }
  //reject 修改状态为 rejected, 并且赋值 reason
  reject(reason){
    if(this.status === PENDING) {
      this.reason = reason;
      this.status = REJECTED;
    }
  }
  //then 方法接收两个参数,onFulfilled, onRejected
  then(onFulfilled, onRejected) {
    //检查处理参数,必须是函数,如果不是,onFulfilled就把 value return出去,onRejected就把 reason throw出去
    const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : value => value;
    const realOnRejected = this.isFunction(onRejected) ? onRejected : reason => { throw reason };

    //then方法的返回值必须是一个promise
    const promise2 = new APromise((resolve, reject) => {
      //如果onFulfilled 或者 onRejected这个函数抛出异常,我们的promise2需停止执行并将异常抛出
      const fulfilledMicrotask = () => {
        //使用微任务执行
        queueMicrotask(() => {
          try {
            const x = realOnFulfilled(this.value);
            this.resolvePromise(promise2, x, resolve, reject);
          } catch (e) {
            this.reject(e);
          }
        })
      }
      //使用微任务执行
      const rejectedMicrotask = () => {
        queueMicrotask(() => {
          try {
            const x = realOnRejected(this.reason);
            this.resolvePromise(promise2, x, resolve, reject)
          }catch (e) {
            this.reject(e)
          }
        })
      }
      //根据不同的状态调用不同的函数
      switch (this.status) {
        case FULFILLED: {
          fulfilledMicrotask()
          break;
        }
        case REJECTED: {
          rejectedMicrotask()
          break;
        }
        case PENDING: {
          //当状态为pending 的时候,需要把.then().then().then()....链式调用下的函数存入数组
          this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask);
          this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask);
        }
      }
    });
    return promise2;
  }
  //catch方法实际走的是then方法
  catch(onRejected) {
    this.then(null, onRejected)
  }
  resolvePromise(promise2, x, resolve, reject ) {
    //如果promise2 和 x 指向相同的对象,就通过TypeError 抛出错误原因,防止死循环
    if( promise2 === x) {
      return reject(new TypeError('promise2 和 x 不能相同'));
    }
    //如果x 是promise 的话,继续执行x 得到返回值y, 继续解析, 这里使用使用微任务(在不影响同步执行的情况下优先执行微任务)
    if(x instanceof APromise) {
      queueMicrotask(() => {
        x.then((y) => {
          this.resolvePromise(promise2, y, resolve, reject)
        }, reject)
      })
    }
    //如果x 不是promise 是一个函数,或者对象
    if(typeof x ==='object' || this.isFunction(x)) {
      //由于 typeof null 返回的是 object
      if(x === null ) {
        return resolve(x);
      }
      let then = null;
      try {
        //把 x.then 赋值 给then
        then = x.then;
      }catch (e) {
        //如果执行x.then 的时候抛出异常
        return reject(e);
      }
      //如果then是函数
      if(this.isFunction(then)) {
        //我们需要一个变量来控制then只执行一次
        let called = false;
        //将x 作为函数的作用域 this 调用,传递两个回调函数作为参数
        try {
          then.call(x, (y) => {
            //通过called 使函数只执行一次
            if(called) return;
            this.resolvePromise(promise2, y, resolve, reject);
            called = true;
          }, (r) => {
            if(called) return;
            called = true;
            reject(r)
          })
        }catch (e) {
          if (called) return;
          reject(e);
        }
      }
    }else {
      //如果x 不是对象或者函数,则以x 为参数执行promise
      resolve(x)
    }
  }
  isFunction(param) {
    return typeof param === 'function';
  }
}


let my = new APromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 2000)
}).then(console.log).then(() => {
  console.log(2)
})