阅读 83

根据规范手写一个promise

规范 | 中文解析

相关术语及概念见上述链接,以下为 promise 实现:

const isFunc = obj => Object.prototype.toString.call(obj) === '[object Function]';
const isObj = obj => Object.prototype.toString.call(obj) === '[object Object]';
// 等待态 规范 2.1.1
const PENDING = 'pending';
// 执行态 规范 2.1.2
const FULFILLED = 'fulfilled';
// 拒绝态 规范 2.1.3
const REJECTED = 'rejected';

class MyPromise {
  constructor(fn) {
    this.status = PENDING;
    this.value = undefined;
    this.filfulledQueues = [];
    this.rejectedQueues = [];
    try {
      fn(this._resolve.bind(this), this._reject.bind(this));
    } catch (err) {
      this._reject(err);
    }
  }
  //传入 promise 的第一个参数 resolve
  _resolve(val) {
    if (val instanceof MyPromise) {
      val.then(this._resolve, this._reject);
    } else if (isObj(val) || isFunc(val)) {
      try {
        if (isFunc(val.then)) {
          val.then(this._resolve, this._reject);
        }
      } catch (e) {
        this._reject(e);
      }
    }
    this._execCallback(FULFILLED, this.filfulledQueues, val);
  }
  //传入 promise 的第二个参数 reject
  _reject(val) {
    this._execCallback(REJECTED, this.rejectedQueues, val);
  }
  _execCallback(status, list, val) {
    //规范 2.2.4 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用,且被作为函数调用(即没有 this 值)
    setTimeout(() => {
      if (this.status !== PENDING) {
        return;
      }
      this.status = status;
      this.value = val;
      let cb;
      //规范 2.2.6
      while ((cb = list.shift())) {
        cb(val);
      }
    });
  }
  //规范 2.3 Promise 解决过程 [[Resolve]](promise, x)
  _resolvePromise(newPromise, x, resolve, reject) {
    if (newPromise === x) {
      //规范 2.3.1
      return reject(new TypeError('循环引用'));
    }
    if (x instanceof MyPromise) {
      //规范 2.3.2
      x.then(resolve, reject);
    } else if (isObj(x) || isFunc(x)) {
      //规范 2.3.3
      try {
        //规范 2.3.3.3
        if (isFunc(x.then)) {
          x.then(resolve, reject);
        } else {
          //规范 2.3.3.4
          resolve(x);
        }
      } catch (e) {
        //规范 2.3.3.3.4
        reject(e);
      }
    } else {
      //规范 2.3.4
      resolve(x);
    }
  }
  //规范 2.2
  then(onFulfilled, onRejected) {
    let newPromise;
    //规范 2.2.1,2.2.7.3
    onFulfilled = isFunc(onFulfilled) ? onFulfilled : val => val;
    //规范 2.2.1,2.2.7.4
    onRejected = isFunc(onRejected)
      ? onRejected
      : err => {
          throw err;
        };
    //规范 2.2.7 then 方法必须返回一个 promise 对象:promise2 = promise1.then(onFulfilled, onRejected);
    return (newPromise = new MyPromise((onFulfilledNext, onRejectedNext) => {
      // onFulfilledNext, onRejectedNext 即该 then 的下一个 then 里传的 resolve 和 reject
      if (this.status === FULFILLED || this.status === REJECTED) {
        //规范 2.2.4 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用
        setTimeout(() => {
          // 规范 2.2.7.1 不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve(走_resolvePromise方法),只有出现异常时才会被 rejected。
          try {
            //规范 2.2.2,2.2.3,2.2.5
            const x = this.status === FULFILLED ? onFulfilled(this.value) : onRejected(this.value);
            this._resolvePromise(newPromise, x, onFulfilledNext, onRejectedNext);
          } catch (e) {
            //规范 2.2.7.2  这里如果x为捕获的err(即 onRejected 不是函数 2.2.7.4)也会进入
            onRejectedNext(e);
          }
        });
      } else if (this.status === PENDING) {
        //规范 2.2.6.1
        this.filfulledQueues.push(() => {
          try {
            //规范 2.2.2,2.2.5
            const x = onFulfilled(this.value);
            this._resolvePromise(newPromise, x, onFulfilledNext, onRejectedNext);
          } catch (e) {
            //规范 2.2.7.2
            onRejectedNext(e);
          }
        });
        //规范 2.2.6.2
        this.rejectedQueues.push(() => {
          try {
            //规范 2.2.3,2.2.5
            const x = onRejected(this.value);
            this._resolvePromise(newPromise, x, onFulfilledNext, onRejectedNext);
          } catch (e) {
            //规范 2.2.7.2
            onRejectedNext(e);
          }
        });
      }
    }));
  }
  //catch 方法
  catch(onRejected) {
    return this.then(null, onRejected);
  }
  //finally 方法
  finally(cb) {
    return this.then(
      val => {
        MyPromise.resolve(cb()).then(() => val);
      },
      err => {
        MyPromise.resolve(cb()).then(() => {
          throw err;
        });
      }
    );
  }
  //resolve 方法
  static resolve(params) {
    return new MyPromise(resolve => {
      resolve(params);
    });
  }
  //reject 方法
  static reject(err) {
    return new MyPromise((resolve, reject) => {
      reject(err);
    });
  }
  //all 方法
  static all(params) {
    let count = 0;
    let valueList = [];
    const promises = Array.from(params);
    return new MyPromise((resolve, reject) => {
      promises.forEach((item, index) => {
        if (!item instanceof MyPromise) {
          item = MyPromise.resolve(item);
        }
        item.then(r => {
          valueList[index] = r;
          if (promises.length === ++count) {
            resolve(valueList);
          }
        }, reject);
      });
    });
  }
  //race 方法
  static race(params) {
    const promises = Array.from(params);
    return new MyPromise((resolve, reject) => {
      promises.forEach(item => {
        if (!item instanceof MyPromise) {
          item = MyPromise.resolve(item);
        }
        item.then(resolve, reject);
      });
    });
  }
}
复制代码

实践中要确保 onFulfilledonRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。 本实现代码采用 setTimeout(宏任务)来实现异步任务,而 chrome 里的 promise 实现则是采用微任务(%EnqueueMicrotask)的方式,故略有不同。

chromepromise 实现参考源码版本小于 5.6.100src/js/promise.js 文件,其中 PromiseEnqueue 方法里的 C 函数 %EnqueueMicrotaskPromiseHandle 加入到 JS运行时 的微任务队列中。

其中因为 chrome 版本的不断迭代, 在版本 5.6.100 里的 hash6f94a8 的提交里重写了整个 PromiseEnqueue,然后在后续版本 6.1.395 里的 hashbba473 的提交里完全删除了 promise.js),最终由 JS 实现完全迭代为 C 开发实现。