实现 Promise.all 的关键点
当我们实现 Promise.all
方法时,有几个关键点需要注意,以确保其正确性和兼容性。以下是一些重要的考虑因素:
-
输入类型检查:
Promise.all
接受一个可迭代对象(通常为数组)作为参数。首先需要验证传入的参数是否为可迭代类型。如果不是,应该抛出一个TypeError
。 -
返回值:
Promise.all
返回一个新的 Promise 对象,该对象在所有传入的 promise 全部解决或任何一个 promise 被拒绝后解决或拒绝。 -
并行处理:所有的 promise 是并行执行的,而不是按顺序。这意味着不应该使用任何阻塞操作来等待每个 promise 解决。
-
结果顺序:即使传入的 promise 以不同的顺序解决,返回的结果数组中的元素也必须与传入数组中的 promise 顺序一致。因此,需要在内部维护一个用于跟踪结果顺序的数据结构。
-
错误处理:如果其中任何一个 promise 拒绝,整个
Promise.all
调用就会立即拒绝,并携带第一个被拒绝的错误信息。这要求对每个单独的 promise 设置错误处理机制。 -
异步行为:确保最终返回的新 Promise 对象是异步决议的,即使所有输入 promises 都已经完成,这也是 JavaScript 事件循环和微任务队列运行机制的一部分。
下面是一个简单实现示例:
function myPromiseAll(iterable) {
return new Promise((resolve, reject) => {
if (typeof iterable[Symbol.iterator] !== 'function') {
return reject(new TypeError(`${typeof iterable} is not iterable`));
}
const results = [];
let remaining = iterable.length;
if (remaining === 0) {
return resolve(results);
}
const processResult = (index, value) => {
results[index] = value;
remaining -= 1;
if (remaining === 0) {
resolve(results);
}
};
iterable.forEach((promise, index) => {
Promise.resolve(promise).then(
value => processResult(index, value),
reason => reject(reason)
);
});
});
}
这个实现示例展示了如何使用基本逻辑来模拟 Promise.all
的行为。通过将所有输入 promises 转换为已解决状态,我们可以更轻松地管理它们,无论它们是已经解决、尚未解决还是被拒绝。同时,这种方法也能确保即使输入中含有非 Promise 值时,函数也能正常工作,因为 Promise.resolve()
会自动将这些值转换为已解决状态的 Promise。