Skip to content

promise 实现

规范 | 中文解析

总览

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

javascript
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.callbacks = [];
    let resolve = (val) => {
      this._execCallback(FULFILLED, val);
    };
    let reject = (reason) => {
      this._execCallback(REJECTED, reason);
    };
    try {
      fn(resolve, reject);
    } catch (err) {
      this._reject(err);
    }
  }
  _execCallback(status, val) {
    if (this.status !== PENDING) {
      return;
    }
    this.status = status;
    this.value = val;
    this.callbacks.forEach((cb) => cb());
  }
  //规范 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((y) => {
        this._resolvePromise(newPromise, y, resolve, reject);
      }, reject);
      //规范 2.3.3
    } else if (isObj(x) || isFunc(x)) {
      if (x === null) {
        return resolve(x);
      }
      let then = undefined;
      try {
        //规范 2.3.3.1 把 x.then 赋值给 then
        then = x.then;
      } catch (err) {
        //规范 2.3.3.2
        return reject(err);
      }
      //规范 2.3.3.3
      if (isFunc(then)) {
        let called = false;
        try {
          then.call(
            x,
            (y) => {
              if (called) return;
              called = true;
              this._resolvePromise(newPromise, y, resolve, reject);
            },
            (r) => {
              if (called) return;
              called = true;
              reject(r);
            },
          );
        } catch (err) {
          if (called) return;
          reject(err);
        }
      } else {
        //规范 2.3.3.4
        resolve(x);
      }
    } else {
      //规范 2.3.4
      resolve(x);
    }
  }
  //规范 2.2 promise.then(onFulfilled, onRejected)
  then(onFulfilled, onRejected) {
    //规范 2.2.1.1,2.2.7.3
    onFulfilled = isFunc(onFulfilled) ? onFulfilled : (val) => val;
    // //规范 2.2.1.2,2.2.7.4
    onRejected = isFunc(onRejected)
      ? onRejected
      : (err) => {
          throw err;
        };
    const promise2 = new MyPromise((resolve, reject) => {
      const fn = () => {
        //规范 2.2.4, 2.2.5 onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用,且被作为函数调用(即没有 this 值)
        setTimeout(() => {
          try {
            const x = this.status === FULFILLED ? onFulfilled(this.value) : onRejected(this.value);
            //规范 2.2.7.1
            this._resolvePromise(promise2, x, resolve, reject);
          } catch (err) {
            //规范 2.2.7.2
            reject(err);
          }
        });
      };
      // 规范 2.2.6
      this.status === PENDING ? this.callbacks.push(fn) : fn();
    });
    // 规范 2.2.7
    return promise2;
  }
  //catch 方法
  catch(onRejected) {
    return this.then(null, onRejected);
  }
  //finally 方法
  finally(cb) {
    return this.then(
      (val) => {
        return MyPromise.resolve(cb()).then(() => val);
      },
      (err) => {
        return 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) {
    return new MyPromise((resolve, reject) => {
      let count = 0;
      let valueList = [];
      const promises = Array.from(params);
      if (promises.length === 0) {
        return resolve(valueList);
      }
      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) {
    return new MyPromise((resolve, reject) => {
      const promises = Array.from(params);
      if (promises.length === 0) {
        return resolve();
      }
      promises.forEach((item) => {
        if (!item instanceof MyPromise) {
          item = MyPromise.resolve(item);
        }
        item.then(resolve, reject);
      });
    });
  }
  //用于 promise test
  static deferred() {
    const result = {};
    result.promise = new MyPromise((resolve, reject) => {
      result.resolve = resolve;
      result.reject = reject;
    });
    return result;
  }
}

module.exports = MyPromise;

promise 测试

手写的 Promise 可通过promises-aplus-tests测试是否符合规范,Promise 内部添加 deferred 静态方法并导出:

js
  static deferred() {
    const result = {};
    result.promise = new MyPromise((resolve, reject) => {
      result.resolve = resolve;
      result.reject = reject;
    });
    return result;
  }
  module.exports = MyPromise;

然后执行命令:

bash
promises-aplus-tests MyPromise

测试结果

chrome 里的实现

实践中要确保 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 开发实现。