在 ES10 中,新增了一个非常有用的语法:for await ...of
。这个语法可以让我们更方便地遍历异步迭代器,并且使得我们的代码更加简洁易读。在本文中,我们将深入介绍 for await ...of
的用法,并且提供一些实际的例子来帮助你更好地理解它。
异步迭代器
在介绍 for await ...of
之前,我们需要先了解一下异步迭代器。异步迭代器是一种特殊的迭代器,它可以遍历异步数据源并返回一个 Promise。异步迭代器的一个常见例子是数据库查询,因为查询结果通常需要异步获取。
异步迭代器的定义如下:
async function* asyncGenerator() { yield 1; yield 2; yield 3; }
上面的代码定义了一个异步迭代器,它可以遍历三个数值:1、2 和 3。这个异步迭代器是一个生成器函数,它使用 async
和 yield
关键字来定义。在生成器函数中,我们可以使用 await
关键字来等待异步操作的结果。
for await ...of 的用法
现在我们已经了解了异步迭代器的概念,接下来我们来看看 for await ...of
的用法。for await ...of
可以用于遍历异步迭代器,并且在每次迭代中等待 Promise 的解析。
for await ...of
的语法如下:
for await (const item of asyncIterable) { // ... }
其中,asyncIterable
是一个异步迭代器对象,item
是每次迭代返回的值。在每次迭代中,for await ...of
都会等待 Promise 的解析,然后将解析的结果赋给 item
。
下面是一个简单的例子,它使用 for await ...of
遍历一个异步迭代器:
-- -------------------- ---- ------- ----- --------- ---------------- - ----- ------------------- ----- ------------------- ----- ------------------- - ------ ---------- - --- ----- ------ ---- -- ----------------- - ------------------ - -----
上面的代码中,我们定义了一个异步迭代器 asyncGenerator()
,它可以遍历三个 Promise 对象。然后我们使用 for await ...of
遍历这个异步迭代器,并在每次迭代中输出 Promise 的解析结果。
for await ...of 的例子
下面我们来看一些实际的例子,来帮助你更好地理解 for await ...of
的用法。
例子一:遍历文件行
假设我们有一个大文件,我们想要按行读取这个文件并进行处理。由于文件很大,我们不能一次性将整个文件读入内存,所以我们需要使用异步方式来读取文件。下面是一个使用 for await ...of
遍历文件行的例子:
-- -------------------- ---- ------- ----- -- - -------------- ----- --------- ------------------- - ----- ---------- - ------------------------------ ----- ------ - ----------------------- --- - ------ ------ ----- ---------- - - ----- -------------- --- ------- - --- -------------- ----- ------------- - --- --- - --------------------- - ------- ---- --- --- ----- - ---------------- --- ---- - - -- - - ------------ - -- ---- - ----- --------- - -- ------ ------ ----- ---------- - - ----- --------------- - -- ------- - --- --- - --------------------- - ------- ---- --- --- ----- - ---------------- --- ---- - - -- - - ------------- ---- - ----- --------- - - - ------ ---------- - --- ----- ------ ---- -- ---------------------------- - ------------------ - -----
上面的代码中,我们定义了一个异步迭代器 readLines()
,它可以遍历一个文件的每一行。在 readLines()
函数中,我们使用 fs.createReadStream()
创建一个可读流,并使用 getReader()
方法获取一个可读流的读取器。然后我们使用 await
关键字等待读取器的 read()
方法返回一个 Promise,然后解析 Promise 的结果并将其赋给 chunk
和 readerDone
变量。
在每次迭代中,我们将 chunk
转换成字符串,并使用 \n
分隔符将其分割成多个行。然后我们使用 yield
关键字将每一行返回给调用方。在下一次迭代中,我们再次调用 read()
方法,直到整个文件都被读取完毕。
例子二:同时遍历多个异步迭代器
有时候我们需要同时遍历多个异步迭代器,并按照某种方式将它们合并起来。下面是一个使用 for await ...of
同时遍历多个异步迭代器的例子:
-- -------------------- ---- ------- ----- --------- ---------------------------------------- - ----- --------- - --------------------- -- ---------------------------- ----- ------------------ - ----- - ------ ---- - - ----- ---------------------------- -- ----------- -- ------ - ------------------------------------------ --- - ---- - ----- ------ - - - ----- --------- ----------------- - ----- ------------------- ----- ------------------- ----- ------------------- - ----- --------- ----------------- - ----- --------------------- ----- --------------------- ----- --------------------- - ------ ---------- - --- ----- ------ ---- -- ---------------------------------------- ------------------- - ------------------ - -----
上面的代码中,我们定义了一个异步迭代器 combineAsyncIterators()
,它可以同时遍历多个异步迭代器,并将它们合并成一个。在 combineAsyncIterators()
函数中,我们使用 map()
方法将每个异步迭代器转换成迭代器对象,并将这些对象存储在 iterators
数组中。然后我们使用 Promise.race()
方法等待所有迭代器中的下一个值,并返回最先解析的 Promise 的结果。如果某个迭代器已经完成了遍历,则我们将其从 iterators
数组中移除。
在下面的代码中,我们定义了两个异步迭代器 asyncGenerator1()
和 asyncGenerator2()
,它们分别可以遍历三个 Promise 对象。然后我们使用 combineAsyncIterators()
同时遍历这两个异步迭代器,并在每次迭代中输出 Promise 的解析结果。
总结
for await ...of
是一个非常有用的语法,它可以让我们更方便地遍历异步迭代器,并且使得我们的代码更加简洁易读。在本文中,我们介绍了异步迭代器的概念,然后深入介绍了 for await ...of
的用法,并提供了一些实际的例子来帮助你更好地理解它。如果你在开发异步代码时遇到了困难,不妨试试使用 for await ...of
语法来简化你的代码。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/65fa8ea8d10417a22266a8e7