Promise实现

1,436 阅读3分钟

Promise实现

这里超级安利大家去看《深入浅出nodejs》4.3.2 章节,别问我为啥老是安利这个,问就真的好看啊!!

Promise 规范

promise的规范有一大堆,但是es6采用了Promise A+ 规范

相关文档 Promise A+规范的友情解释链接 规范说明英文版

相信大家看完上面给的那个连接已经对整个promise的执行过程都有个了解了。 这里总结下

  • 具有then方法,then()方法继续返回Promise对象,以实现链式调用。
  • Promise操作只会处在3种状态的一种:未完成态(Pending)、完成态(Fulfilled)和失败态(Rejected)。
  • Promise的状态只会出现从未完成态向完成态或失败态转化,不能逆反。完成态和失败态不能互相转化。
  • Promise的状态一旦转化,将不能被更改。
  • 接受完成态、错误态的回调方法。在操作完成或出现错误时,将会调用对应方法

实现

以下为菜狗子根据规范约定实(chao)现(xi),有错欢迎指出。

大佬们封装的promise实现测试工具,有实现完成的,可以用这个测试下是否符合标准。

大佬们封装好的例子想要看更多的,可以看这里。菜狗子的实现参考其中belofte.js为方便理解(就是懒)砍掉了许多类型判断。

注释写的比我多,讲的比我细致的一篇文章

const PENDING = "Pending";
const FULFILLED = "Fulfilled";
const REJECTED = "Rejected";

const root = typeof window === "undefined" ? global : window;
const isFunction = data => typeof data === "function";
const isMyPromise = fn => fn instanceof MyPromise;
const isObject = data =>
  data && (typeof data === "object" || typeof data === "function");
// 因为promise是微任务,我们尽可能的去模拟
const nextTick = (function() {
  if (typeof root.process === "object" && isFunction(root.process.nextTick)) {
    // node环境
    return function(fn) {
      // process.nextTick 是微任务
      root.process.nextTick(fn);
    };
  } else {
    // 浏览器环境
    return function(fn) {
      // setTimeout 是宏任务
      root.setTimeout(fn, 0);
    };
  }
})();

// 将promise由中间态到终态
const promiseResolutionProcedure = function(promise, result, async = true) {
  if (promise === result) {
    /**
     * 因为promise 如果收到的value是一个promise会等待他的结果。
     * 所以如果接受到的value是本身就递归了。
     *
     * @see https://promisesaplus.com/ 2.3.1 条规定
     */
    promise._reject(new TypeError("Chaining cycle detected for promise"));
    return;
  }
  // 如果接收到的是个promise
  if (isMyPromise(result)) {
    switch (result._state) {
      case FULFILLED: {
        nextTick(function() {
          promise._resolve(result._value);
        });
        break;
      }
      case REJECTED: {
        nextTick(function() {
          promise._reject(result._reason);
        });
        break;
      }
      case PENDING: {
        const _resolve = result._resolve;
        const _reject = result._reject;

        result._resolve = function(value) {
          _resolve.call(result, value);
          promise._resolve(value);
        }.bind(result);

        result._reject = function(reason) {
          _reject.call(result, reason);
          promise._reject(reason);
        }.bind(result);
        break;
      }
    }
    return;
  }

  // 如果接受到的是个thenable 对象
  if (isObject(result) && isFunction(result.then)) {
    /**
     * 多次调用只有第一次有效
     *
     * @see https://promisesaplus.com/ 2.3.3.3.3 条规定
     */
    let flag = false;
    const _resolve = function(value) {
      if (flag) {
        return;
      }
      flag = true;
      promiseResolutionProcedure(promise, value);
    };
    const _reject = function(reason) {
      if (flag) {
        return;
      }
      flag = true;
      promise._reject(reason);
    };
    const thenTemp = function() {
      try {
        result.then(_resolve, _reject);
      } catch (error) {
        _reject(error);
      }
    };
    if (async) {
      nextTick(thenTemp);
    } else {
      thenTemp();
    }
    return;
  }

  promise._resolve(result);
  return;
};

class MyPromise {
  constructor(resolver) {
    if (!isFunction(resolver)) {
      throw new TypeError("Promise resolver undefined is not a function");
    }
    /** @type { PENDING | FULFILLED | REJECTED} */
    this._state = PENDING;

    this._value = undefined;
    this._reason = undefined;

    this._isPromise = true;
    /**
     * 因为同一个promise可以被then 多次。
     * 这里的多次不是指链式调用!!!! 
     * 这里理解了好久TAT
     */ 
    this._resolveFnQueues = [];
    this._rejectFnQueuse = [];

    promiseResolutionProcedure(this, { then: resolver }, false);
  }

  _resolve(value) {
    if (this._state !== PENDING) {
      return;
    }
    this._state = FULFILLED;
    this._value = value;
    if (this._resolveFnQueues.length) {
      nextTick(() => {
        this._resolveFnQueues.forEach(cb => cb(value));
        this._resolveFnQueues.length = 0;
        this._rejectFnQueuse.length = 0;
      });
    }
  }

  _reject(reason) {
    if (this._state !== PENDING) {
      return;
    }
    this._state = FULFILLED;
    this._reason = reason;
    if (this._rejectFnQueuse.length) {
      nextTick(() => {
        this._rejectFnQueuse.forEach(cb => cb(reason));
        this._resolveFnQueues.length = 0;
        this._rejectFnQueuse.length = 0;
      });
    }
  }
  // then注册一个监听,在这个promise onFulfilled 或者 onRejected
  then(onFulfilled, onRejected) {
    onFulfilled = isFunction(onFulfilled) ? onFulfilled : MyPromise.resolve;
    onRejected = isFunction(onRejected) ? onRejected : MyPromise.reject;
    const chainPromise = new MyPromise(function() {});

    const nextOnFulfilled = function(value) {
      let result;
      try {
        result = onFulfilled(value);
        promiseResolutionProcedure(chainPromise, result);
      } catch (error) {
        chainPromise._reject(error);
      }
    };

    const nextOnRejected = function(reason) {
      let result;
      try {
        result = onRejected(reason);
        promiseResolutionProcedure(chainPromise, result);
      } catch (error) {
        chainPromise._reject(error);
      }
    };

    switch (this._state) {
      case FULFILLED: {
        nextTick(() => {
          nextOnFulfilled(this._value);
        });
        break;
      }
      case REJECTED: {
        nextTick(() => {
          nextOnRejected(this._reason);
        });
        break;
      }
      case PENDING: {
        this._resolveFnQueues.push(nextOnFulfilled);
        this._rejectFnQueuse.push(nextOnRejected);
      }
    }

    return chainPromise;
  }

  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  toString() {
    switch (this._state) {
      case PENDING:
        return "Promise { <pending> }";
      case FULFILLED:
        return "Promise { " + this._value + " }";
      case REJECTED:
        return "Promise { <rejected> " + this._reason + " }";
    }
  }

  static resolve(value) {
    return new MyPromise(resolve => resolve(value));
  }

  static reject() {
    return new MyPromise((resolve, reject) => reject(value));
  }
}

补充

async 实现

async 本质就是将 Generator 函数和自动执行器,包装在一个函数里

阮一峰大大的文章讲的炒鸡清楚了。这里的内容也来自于那篇文章,本人也就温习实现一下.

// async 的写法
async function fn(args){
  // ...
}

// 等同于
function fn(args){ 
  return spawn(function*() {
    // ...
  }); 
}
//spawn 的实现方式
function spawn(genF) {
  return new Promise(function(resolve, reject) {
    var gen = genF();
    step(function() { return gen.next(undefined); });
    function step(nextF) {
      try {
        var next = nextF();
      } catch(e) {
        return reject(e); 
      }
      if(next.done) {
        return resolve(next.value);
      } 
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });      
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
  });
}