手写Promise核心原理(二)

242 阅读3分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

前面写了 Promise的入门和相关方法的使用Promise的关键问题手写Promise核心原理(一), 需要的童鞋请移步。这篇文章写下Promise相关方法的核心原理:

一、手写Promise.prototype.then()

我们知道then方法的作用是分别指定resolve和reject的回调函数,返回一个新的Promise实例。

(不了解的请翻看之前的文章Promise的入门和相关方法的使用

then方法内部具体有哪些操作呢?

  1. 接收的参数为resolve回调函数和reject回调函数,指定回调函数的默认值。
  2. 返回一个新的promise实例。
  3. 根据promise实例当前不同的状态调用不同的回调函数。
  4. 将回调函数的结果绑定到新的promise上去。 前两个操作是比较简单的:
  • 第一个操作为接收两个参数,所以我们只需给then方法设置两个形参onResolved和onRejected。
  • 第二个操作是返回一个新的Promise实例,所以在then方法中直接return new Promise。 第三四个操作相对复杂些,需要展开分析:
  • 第三个操作是根据不同的状态调用不同的回调函数,promise实例的当前状态总共有三种可能性:pending、fulfilled、rejected。 (1)当状态为fulfilled时,调用onResolved回调函数;

(2)当状态为rejected时,调用onRejected回调函数;

(3)当状态为pending时,要将onResolved和onRejected两个回调函数一起传入callbacks数组中,等待后续调用执行。

  • 第四个操作将回调函数执行后的结果绑定到新的Promise上,这里由于无论哪种状态都要做这个处理,所以我们封装成一个handler方法,减少重复代码。由于要将返回结果绑定到新的promise上,所以要将handler方法写在该Promise中。回调函数执行的过程中可能会出现异常,所以使用try/catch捕获异常。回调函数的执行结果分为以下三类,分别对应不同的返回结果:

(1)抛出异常,返回promise的结果为失败。

(2)返回的是promise,返回promise的结果就是这个结果。

(3)返回的不是promise,返回promise为成功,value就是返回值。

代码如下:

Promise1.prototype.then = function(onResolved, onRejected) {
  var _this = this;
  // 指定回调函数的默认值
  onResolved = typeof onResolved == "function" ? onResolved : value => value;
  onRejected = typeof onRejected == "function" ? onRejected : reason => { throw reason; };
  return new Promise1(function(reslove, reject) {
    // handler方法的作用:执行回调函数并将返回值分类传递给最后需要返回的promise
    function handler(callback) {
      try {
        var result = callback(_this.data);
        if (result instanceof Promise1) {
          // 返回的是promise
          result.then(resolve, reject);
        } else {
          // 返回的不是promise
          resolve(result);
        }
      } catch (error) {
        // 抛出异常
        reject(error);
      }
    }
    if (_this.status == PENDING) {
      // pending状态时要把回调函数给存起来,后面状态改变后再调用
      _this.callbacks.push({
        onResolved(value) {
          // 执行后也需要将返回值传给最后要返回的promise
          handler(onResolved);
        },
        onRejected(reason) {
          handler(onRejected);
        }
      });
      console.log(_this.callbacks);
    } else if (_this.status == FULFILLED) {
      handler(onResolved);
    } else {
      handler(onRejected);
    }
  });
};