模拟实现Promise(下)

上篇文章中我们实现了一个具有基础功能的MyPromise,除了内部使用的_resolve_reject外,我们只实现了Promise.prototype.then,那么这篇文章中,我们来实现更多 API。

Promise.prototype.catch

catch的参数是onRejected,即拒绝事件的回调,它返回一个新的 Promise。如果当前 Promise 是决议状态的话,则决议值会透传给新的 Promise 上注册的决议事件回调。

class MyPromise {
  // ...
  catch(onRejected) {
    return this.then(null, onRejected);
  }
}

它的实现利用了.then只能接收函数类型参数的特性,显式将onFulfilled设置为null

Promise.prototype.finally

这是一个 ES2018 的新特性。finally方法返回一个 Promise,它接收的参数称为onFinally,其特点是,无论当前 Promise 被决议或者是被拒绝,onFinally都会执行。这为在 Promise 是否成功完成后都需要执行的代码提供了一种方式。需要注意的是,只有在onFinally中 throw 或返回被拒绝的 Promise 时,onFinally才会返回被相应原因拒绝的 Promise,否则返回的 Promise 状态与上一个 Promise 保持一致。

class MyPromise {
  // ...
  finally(cb) {
    return this.then(
      value => MyPromise.resolve(cb()).then(() => value),
      reason =>
        MyPromise.resolve(cb()).then(() => {
          throw reason;
        })
    );
  }
}

Promise.reject

实例上的方法实现完之后,我们来实现 Promise 上的静态方法。Promise.reject返回一个拒绝状态的 Promise

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

Promise.resolve

Promise.reject类似,Promise.resolve返回一个被决议的 Promise。但是后者多了一些细节,即如果传参是 Promise 实例的话,则直接返回这个实例。因此Promise.resolve常被用来保障某个值是 Promise。

class MyPromise {
  // ...
  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve => resolve(value));
  }
}

Promise.all

Promise.all接收一个数组作为参数,参数数组中的成员可以是 Promise,也可以是普通值。它的返回值是一个 Promise,该返回值 Promise 被决议时表示参数数组中所有成员均被决议,此时返回值 Promise 决议值为一个数组,与参数数组的决议值一一对应;该返回值 Promise 被拒绝时,说明参数数组中有成员被拒绝,此时返回值 Promise 的拒绝原因即为那个被拒绝的成员的拒绝原因。

Promise.all有一个特殊情况,当传递空数组时,返回决议值为空数组的 Promise。

class MyPromise {
  // ...
  static all(promises) {
    if (promises.length === 0) return MyPromise.resolve([]);
    return new MyPromise((resolve, reject) => {
      let resolvedValues = [];
      let resolvedCount = 0;
      for (let i = 0; i < promises.length; i++) {
        MyPromise.resolve(promises[i]).then(
          value => {
            resolvedValues[i] = value;
            if (++resolvedCount === promises.length) {
              resolve(resolvedValues);
            }
          },
          reason => reject(reason)
        );
      }
    });
  }
}

Promise.reject

传参形式与Promise.all相同,该函数的返回值是一个 Promise,当返回值 Promise 被决议时,说明参数数组中有成员被决议了,返回值的决议值即为该成员的决议值;当返回值 Promise 被拒绝时,说明参数数组中有成员被拒绝了,返回值的拒绝原因即为该成员的拒绝原因。

Promise.race传递空数组时,返回值 Promise 会一直处于 Pending 状态,永远不会被决议或者拒绝,我们要避免这种情况。

class MyPromise {
  // ...
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        MyPromise.resolve(promises[i]).then(
          value => resolve(value),
          reason => reject(reason)
        );
      }
    });
  }
}

Promise.allSettled

这同样是一个 ES2018 新增的 API。它的传参与Promise.all一致,但返回值 Promise 一定会被决议,且决议值同样是数组,数组成员的形式要么是{status: 'fulfilled', value: FulfilledValue},要么是{status: 'rejected', reason: RejectedReason},具体是哪一种,取决于对应位置上的参数数组成员被决议还是拒绝。

static allSettled(promises) {
    return Promise.all(
      Array.from(promises, p => {
        return Promise.resolve(p).then(
          value => ({ status: "fulfilled", value }),
          reason => ({ status: "rejected", reason })
        );
      })
    );
  }
}

1334 Words

2019-02-10 21:01 +0800

comments powered by Disqus