模拟实现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 })
);
})
);
}
}