Node.js中的异步生成器与异步迭代详解
异步迭代
异步迭代可以理解为一种异步操作处理流程,我们通过一个example框架来讲解其中的机制。
假设有这样一种场景,我们需要上传多张图片到远端服务器,并在所有的图片上传完成之后返回一个数组,数组中的每个元素为每一张图片上传成功后返回的结果。我们可以通过以下代码实现:
async function uploadPictures(pictures) {
const results = [];
for (const picture of pictures) {
const result = await uploadPicture(picture);
results.push(result);
}
return results;
}
上面的代码中使用了 for-of
循环来遍历 pictures
数组,每次遍历将图片上传到远端服务器,并将返回的结果 push 到 results 数组中。同时,使用 await
关键字等待每次异步操作完成后才进行下一次循环和操作。
但上面的代码存在一些问题,比如示例中的操作实际上是顺序执行的(同步运行),存在阻塞操作,当上传图片数量过多时,代码会因为阻塞而变得非常慢,降低系统的性能。为了解决这些问题,异步迭代应运而生。
使用异步迭代进行优化:
async function* uploadPictures(pictures) {
for (const picture of pictures) {
yield uploadPicture(picture);
}
}
async function run() {
const iterator = uploadPictures([1, 2, 3, 4, 5]);
for await (const result of iterator) {
console.log(result);
}
}
上面的代码中,我们使用异步迭代器 async function*
重构了该函数的实现,将其变为一个生成器函数(generator function),其目的是让函数异步迭代图片上传的过程,即:
-
使用
yield
将每张图片上传操作返回,将该操作封装在生成器函数中。 -
使用异步迭代器遍历生成器函数,循环中的每一次异步操作都实现了异步执行(非阻塞)。
异步生成器
异步生成器是异步迭代的实现基础,它本身就是一个生成器函数,但可以通过 async
和 await
声明异步操作。在生成异步数据时,可以使用 yield
关键字将每个异步返回值返回到迭代器中,而异步操作执行完毕后也可以通过 return
关键字返回值,或者通过 throw
关键字抛出异常。
我们通过一个异步生成器的例子来帮助理解其机制:
async function* generateNumbers() {
let i = 0;
while (i < 5) {
console.log('start');
yield new Promise(resolve =>
setTimeout(() => resolve(i++), 1000)
);
console.log('end');
}
}
async function run() {
const iterator = generateNumbers();
for await (const number of iterator) {
console.log(number);
}
}
上面的代码中,通过异步生成器 generateNumbers()
实现异步生成 0-5 的整数,并使用异步迭代器 for await (const number of iterator)
获取异步生成器生成的每个值,并打印到控制台上。
需要注意的是,在 generateNumbers()
函数中使用了 yield new Promise(resolve => setTimeout(() => resolve(i++), 1000));
这条语句的作用是暂停异步流程并等待该 Promise 对象的完成,然后再进一步执行下一步操作。
示例说明
异步迭代示例
我们继续使用上面的上传图片的示例来说明异步迭代的使用。
async function* uploadPictures(pictures) {
for (const picture of pictures) {
yield uploadPicture(picture);
}
}
async function run() {
const iterator = uploadPictures([1, 2, 3, 4, 5]);
for await (const result of iterator) {
console.log(result);
}
}
上面的代码中,uploadPictures()
函数就是一个异步生成器,它将上传每一张图片的操作异步生成,然后使用异步迭代器遍历每次异步操作的结果,并将结果打印到控制台上。
异步生成器示例
我们再来看一个异步生成器示例,实现打印斐波那契数列前 n 项数。
async function* fibonacci(limit) {
let [prev, curr] = [0, 1];
for (let i = 0; i < limit; i++) {
await new Promise(resolve => setTimeout(resolve, 1000));
[prev, curr] = [curr, prev + curr];
yield curr;
}
}
async function run() {
const iterator = fibonacci(10);
for await (const number of iterator) {
console.log(number);
}
}
上述代码中,我们声明了一个异步生成器函数 fibonacci()
,该函数生成了斐波那契数列的前 n 项,每次生成一个数值前会等待一秒钟,然后使用 yield
返回生成数据。最后在 run()
函数中使用异步迭代器遍历生成器函数返回的值,并将每个异步生成的值打印到控制台上。
使用异步生成器和异步迭代器可以更好地管理异步代码及其调度,使得代码更清晰、更可读且更易于调试。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Node.js中的异步生成器与异步迭代详解 - Python技术站