异步数组迭代:突破 Symbol.iterator 的限制
2023-11-07 07:44:40
众所周知,Symbol.iterator 为数组提供了强大的迭代能力,使我们能够轻松地遍历其元素。然而,当我们遇到需要处理异步操作的数组时,Symbol.iterator 似乎遇到了局限。想象一个场景:数组中包含异步函数,我们希望在遍历过程中等待所有异步操作完成。此时,我们不禁思索:除了常见的 Promise.all 方法,是否还存在其他途径来实现这一需求?
跳出 Promise.all 的思维框架
Promise.all 作为一种可靠的解决方案,无疑可以满足我们的需求。它能够聚合多个 Promise,并在所有 Promise 完成后返回一个新的 Promise。然而,我们不妨跳出 Promise.all 的思维框架,探索更加灵活多变的实现方式。
利用 Generator 函数
Generator 函数为我们提供了另一种选择。它是一个特殊类型的函数,能够暂停和恢复执行。通过 Generator 函数,我们可以创建一种自定义的迭代器,允许我们逐个处理数组中的元素,并在每个异步操作完成后继续执行。
async function* asyncArrayIterator(array) {
for (const element of array) {
if (typeof element === 'function') {
yield await element();
} else {
yield element;
}
}
}
在这个自定义的迭代器中,我们逐个遍历数组元素,判断它们是否是函数。如果是函数,则使用 await 等待其异步操作完成并返回结果。否则,直接返回元素本身。
应用 for await...of 循环
有了自定义迭代器,我们可以使用 for await...of 循环轻松地遍历数组并等待异步操作完成:
async function main() {
const array = [
async () => 1,
async () => 2,
3,
async () => 4
];
for await (const element of asyncArrayIterator(array)) {
console.log(element);
}
}
main();
自定义迭代器的优势
与 Promise.all 相比,自定义迭代器提供了以下优势:
- 渐进处理: 自定义迭代器可以逐个处理元素,无需等待所有异步操作同时完成。
- 取消支持: 如果不再需要剩余的异步操作,可以通过手动终止 Generator 函数来取消它们。
- 灵活性: 自定义迭代器允许我们根据特定需求定制迭代逻辑,例如按需加载或跳过某些元素。
结语
通过利用 Symbol.iterator 和 Generator 函数,我们可以突破 Symbol.iterator 的局限,实现数组中元素的异步回调。自定义迭代器为我们提供了比 Promise.all 更灵活多变的解决方案,可以根据不同的场景和需求进行定制。