Promise 源码:静态方法

1,954 阅读3分钟

前言

最后来看一下 Promise 的几个常用的静态方法的实现:

  • Promise.resolve
  • Promise.reject
  • Promise.all
  • Promise.race

注:本次阅读的是 then/promise 的 4.0.0 版本,源码请戳 这里

解读

在 4.0.0 版本之中,Promise 对象被封装在了 core.js 文件中,常用的静态方法则写在了 index.js 文件中,打开 index.js 文件。

Promise.resolve

Promise.resolve 方法有下面三种使用形式:

Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(theanable);

这三种形式都会产生一个新的 Proimse,从而能够继续 then 链式调用。

Promise.resolve = function (value) {
  return new Promise(function (resolve) { 
    resolve(value);
  });
}

Promise.resolve 的实现,就是 new 一个新的 Promise 实例并调用 resolve 方法,最后返回。

Promise.reject

Promise.reject 与 Promise.resolve 同理,只不过将 resolve 替换成 reject。

Promise.reject = function (value) {
  return new Promise(function (resolve, reject) { 
    reject(value);
  });
}

Promise.all

Promise.all 可以将传入的多个 Promise 实例里都 resolve 成功再返回一个结果数组。

实现的思路就是用一个计数器,从零开始计,每当一个 Promise 实例调用了 resolve,则 +1。知道计数器等于 Promise 实例的数量时,表示全部都执行完了,此时返回结果。

Promise.all = function () {
  var args = Array.prototype.slice.call(arguments.length === 1 && Array.isArray(arguments[0]) ? arguments[0] : arguments)

  return new Promise(function (resolve, reject) {
    if (args.length === 0) return resolve([])
    var remaining = args.length
    function res(i, val) {
      try {
        if (val && (typeof val === 'object' || typeof val === 'function')) {
          var then = val.then
          if (typeof then === 'function') {
            then.call(val, function (val) { res(i, val) }, reject)
            return
          }
        }
        args[i] = val
        if (--remaining === 0) {
          resolve(args);
        }
      } catch (ex) {
        reject(ex)
      }
    }
    for (var i = 0; i < args.length; i++) {
      res(i, args[i])
    }
  })
}

实现的代码里是做减法,跟计数器做加法思路是一致的。代码里 new 了一个新的 Promise,当触发了计数器设定的值(即 0),则调用它的 resolve,从而触发 then 函数。

res 函数里,给每一个 Promise 实例绑定一个 then 方法,当触发 resolve,即触发 then,从而再次调用 res 函数。只有传入的值不再是 Promise 实例,此时就用 args 记录,作为以后返回的结果数组。并重新设置计数器 remaining(做减法)。

remaining 被减到了 0,表示所有传入的 Promise 实例都执行了 resolve,此时可以调用新 new 出来的 Promise 实例的 resolve 。

Promise.race

Promise.race 与 Promise.all 相反,只要传入的多个 Promise 实例只要有一个调用了 resolve 就会触发它的 then 函数。

源码是这样的:

Promise.race = function (values) {
  return new Promise(function (resolve, reject) { 
    values.map(function(value){
      Promise.cast(value).then(resolve, reject);
    })
  });
}

代码里也 new 了一个新的 Promise 实例,给传入的每一个 Promise 实例也都绑定 then 方法。只要有一个 Promise 执行了 then,就直接执行了 resolve。

这里的 Promise.cast 方法是为了返回一个可以调用 then 的 Promise 实例。

这里可以看最新的 源码实现 更好理解:

Promise.race = function (values) {
  return new Promise(function (resolve, reject) {
    values.forEach(function(value){
      Promise.resolve(value).then(resolve, reject);
    });
  });
};

最后

看了 Promise 的静态方法源码,会发现都是基于之前的一整套 Promise 对象来实现的,没有新的知识点。看起来不好实现的代码,却是这样几行代码就实现了,是我想复杂了。

不经感慨,芸芸众生,活到老,学到老啊。