poplark

Hi, 👋 ! 如果您发现有什么错误的地方,点这里可以提 issue,🤝🤝

View My GitHub Profile

19 November 2020

Promise

by poplark

手写 Promise

一. 基本用法

new Promise((resolve, reject) {
  // ...
  // if xxx resolve(xxx)
  // if yyy reject(yyy)
}).then((data) => {
  // ...
}, (err) => {
  // ...
});
new Promise((resolve, reject) {
  // ...
  // if xxx resolve(xxx)
  // if yyy reject(yyy)
}).then((data) => {
  // ...
}).catch((err) => {
  // ...
});

二. 思想说明

一个 Promise 对象内部只会有三种状态: pending, fulfilled, rejected,初始状态永远为 pending,而且一旦转变成 fulfilled 或 rejected 状态,则永远定格为该状态。

当转变为 fulfilled 状态之后,内部会记录 fulfilled 时对应的 data 用于传给 then 中的 onFulfilled 回调函数。 当转变为 rejected 状态之后,内部会记录 rejected 时对应的 reason 用于传给 then 或 catch 中的 onRejected 回调函数。

特别地,由于 Promise 支持链式调用,所以像 then, catch 的返回值都为一个 Promise 对象。

三. 实现步骤拆解

// 1. 定义内部状态
enum MPromiseState {
  pending = 0,
  fulfilled = 1,
  rejected = 2,
}
interface ResolveFunc<T> {
  (data: T): any;
}
interface RejectFunc {
  (reason: any): any;
}
interface Handler<T> {
  (resolve?: ResolveFunc<T>, reject?: RejectFunc): any;
}
type onFulfilledFunc<T> = ResolveFunc<T>;
type onRejectedFunc = RejectFunc;

class MPromise<T> {
  private state = MPromiseState.pending;
  private data: T;
  private reason: any;

  // 12. fulfilled 时执行的回调函数,可由下级 Promise 注册,进而通知到下级 Promise
  private onFulfilled: onFulfilledFunc<T>;
  // 13. rejected 时执行的回调函数,可由下级 Promise 注册,进而通知到下级 Promise
  private onRejected: onRejectedFunc;

  constructor(handler: Handler<T>) {
    // todo - verify handler function
    // 2. 处理 Handler 函数
    // 3. 定义 resolve 和 reject 函数,作为 handler 函数的参数,由程序在 handler 中调用,以改变 Promise 的内部状态,进而唤醒 then 或 catch 中传入的 onFulfilled 或 onRejected 回调函数;
    const resolve: ResolveFunc<T> = (data) => {
      if (this.state !== MPromiseState.pending) {
        return; // 当 Promise 的状态已变为非 pending 时,则不再处理状态的变更
      }
      this.state = MPromiseState.fulfilled;
      this.data = data;
      // 14. 执行 onFulfilled
      this.onFulfilled && this.onFulfilled(this.data);
    }
    const reject: RejectFunc = (reason) => {
      if (this.state !== MPromiseState.pending) {
        return; // 当 Promise 的状态已变为非 pending 时,则不再处理状态的变更
      }
      this.state = MPromiseState.rejected;
      this.reason = reason;
      // 15. 执行 onFulfilled
      this.onRejected && this.onRejected(this.reason);
    }
    // 16. 制造延迟执行函数,确保将 onFulfilled 和 onRejected 函数插入到任务队列尾部
    const delay = (fn: Function): Function => {
      return function (...args) {
        setTimeout(() => {
          fn(...args);
        }, 0);
      }
    }

    try {
      handler(delay(resolve) as ResolveFunc<T>, delay(reject) as RejectFunc); // 捕获 handler 中的异常,若有异常则直接将 Promise 状态改变为 rejected
    } catch (err) {
      (delay(reject) as RejectFunc)(err);
    }
  }

  // 4. 处理 then 函数
  then(onFulfilled?: onFulfilledFunc<T>, onRejected?: onRejectedFunc): MPromise<T> {
    // 返回值永远为一个新的 Promise 对象
    return new MPromise((resolve, reject) => {
      // 5. 由于让上级 Promise 的状态变更或已完结的状态,通知到当前 Promise ?
      // 6. 定义 _onFulfilled 函数,用于让上级 Promise 的状态变为 fulfilled 或已为 fulfilled 时,通知当前 Promise
      const _onFulfilled: onFulfilledFunc<T> = (data) => {
        if (onFulfilled && typeof onFulfilled === 'function') {
          try {
            const result = onFulfilled(data);
            if (result && typeof result.then === 'function') {
              result.then(resolve, reject); // onFulfilled 返回 Promise 时,该 Promise 对象变成为了本 Promise 对象的上级,故需要等该 Promise 完结时,再触发本 Promise 的 resolve 或 reject
            } else {
              resolve && resolve(result);
            }
          } catch (err) {
            reject && reject(err); // onFulfilled 抛出异常时,则将本 Promise 变为 rejected 状态
          }
        } else {
          resolve && resolve(data); // 当 onFulfilled 为非函数时,则直接将上级 Promise 的 data 传给本 Promise
        }
      }
      // 7. 定义 _onRejected 函数,用于让上级 Promise 的状态变为 rejected 或已为 rejected 时,通知当前 Promise
      const _onRejected: onRejectedFunc = (reason) => {
        // 与上面的 _onFulfilled 思路类似
        if (onRejected && typeof onRejected === 'function') {
          try {
            const result = onRejected(reason);
            if (result && typeof result.then === 'function') {
              result.then(resolve, reject); // onRejected 返回 Promise 时,该 Promise 对象变成为了本 Promise 对象的上级,故需要等该 Promise 完结时,再触发本 Promise 的 resolve 或 reject
            } else {
              resolve && resolve(result);
            }
          } catch (err) {
            reject && reject(err); // onRejected 抛出异常时,则将本 Promise 变为 rejected 状态
          }
        } else {
          reject && reject(reason); // 当 onRejected 为非函数时,则直接将上级 Promise 的 reason 传给本 Promise
        }
      }
      switch (this.state) {
        // 8. 上级 Promise 的状态已为 fulfilled 时,执行 then 的 onFulfilled 回调并触发本 Promise 的 resolve
        case MPromiseState.fulfilled:
          _onFulfilled(this.data);
          break;
        // 9. 上级 Promise 的状态已为 rejected 时,执行 then 的 onRejected 回调并触发本 Promise 的 reject
        case MPromiseState.rejected:
          _onRejected(this.reason);
          break;
        // 10. 上级 Promise 的状态为 pending 时,需要向上级 Promise 注册回调函数
        case MPromiseState.pending:
          this.onFulfilled = _onFulfilled; // 向上级 Promise 注册 onFulfilled 回调函数
          this.onRejected = _onRejected; // 向上级 Promise 注册 onRejected 回调函数
          break;
      }
    });
  }

  catch(onRejected?: onRejectedFunc): MPromise<T> {
    // 11. catch 相当于关心上级 Promise 的 rejected 状态,故可以这样调用
    return this.then(undefined, onRejected);
  }
}

到此,一个 Promise 的实现最核心的问题基本已经完成。其他扩展就比较容易了,如

MPromise.resolve = function(data: T): MPromise<T> { return new MPromise((resolve) => resolve(data)); }

但是上面的代码仍然存在部分使用场景无法覆盖的问题,如:

const p = new MPromise((resolve) => resolve('a'));
p.then(x => console.log(`111 ${a}`));
p.then(x => console.log(`222 ${a}`));

那么,这里将永远只打印出来 222 a,原因在于 onFulfilled 和 onRejected 回调函数被覆盖,解决这一问题,需要将 onFulfilled 和 onRejected 改造成数组。

tags: promise - 实现