ES9 中的 `for await...of` 循环与异步代码

在 ES9 中,新增了 for await...of 循环语法来处理异步迭代器,极大地方便了前端开发者处理异步代码。本文将详细介绍这一语法,并通过实例代码进行演示,以帮助读者更好地掌握这一技术。

什么是 for await...of 循环

在 ES6 中,我们有 for...of 循环来遍历一个可迭代对象(如数组、字符串、Map、Set 等)中的每一个元素。而随着 JavaScript 的异步编程模式越来越流行,ES9 也新增了 for await...of 循环语法,用于遍历异步可迭代器(AsyncIterable)中的每一个迭代结果。

一个异步可迭代器是一个接受 Symbol.asyncIterator 键的属性,该属性值为一个返回异步迭代器(AsyncIterator)的函数。异步迭代器是一个包含 .next() 方法的对象,并返回一个 Promise,在迭代完成后会 resolve 该结果。

如何使用 for await...of 循环

下面是一个简单的示例代码,用于遍历一个异步可迭代对象(这里使用 fs.readdir 实现异步文件读取并返回文件名列表的逻辑):

在上面的代码中,我们首先使用 fs.promises.readdir() 方法读取指定路径下所有文件的文件名列表,该方法返回一个 Promise,因此我们使用 async/await 语法来获取迭代器的值。接着我们使用 for await...of 循环遍历这个列表,并输出每一个文件的文件名。

需要注意的是,在 for await...of 循环中,变量 file 的值并不是一个字符串或者数字,而是被异步迭代器后续迭代之后 resolve 出来的值,因此我们需要等待每一个迭代操作的完成。

for...offor await...of 循环的对比

为了更好地理解 for await...of 循环的作用,我们现在来对比一下使用 forfor...of 循环、使用 for awaitfor await...of 循环时的区别。

首先,当我们使用 for 循环来遍历一个 Promise 时,会出现以下的问题:

上面的代码并不能正确输出数组 [1, 2, 3] 中的每一个元素,因为 Promise 实例没有实现迭代器协议。这时候,我们可以将 Promise 实例与 for...of 循环结合起来,将 Promise.resolve() 替换为 Promise[Symbol.iterator]()

在这个例子中,我们首先使用 Promise.resolve() 声明一个 Promise 对象,该对象返回一个包含数组 [1, 2, 3] 等数据的 resolved 状态的 Promise。接着,我们使用 await 操作符获取了一个迭代器,之后使用 for...of 循环遍历迭代器获取数组中的每一个元素。

然而,当我们在上述代码的基础之上尝试使用 for await 循环时,却会收到以下错误提示:

这是因为 p 并不是异步可迭代的,因此我们需要使用 await Promise.resolve() 来创建一个 promiseResolved 后的异步可迭代对象:

在这个例子中,我们首先使用 Promise.resolve() 创建一个 resolved 状态的 Promise,其中包含一个数组 [1, 2, 3]。接着,我们使用 await 操作符获取该 Promise 的迭代器并使用 for await...of 循环遍历异步迭代器。当迭代器被迭代完成后,我们输出了数组中的每一个元素。

综上所述,for await...of 循环可以方便地遍历异步可迭代器,而 for 循环和 for...of 循环则无法直接处理异步迭代器。在实践中,我们需要注意异步代码的写法,使其符合异步编程模式及正确的语法规范。

总结

在本文中,我们学习了 ES9 中的 for await...of 循环,该语法用于处理异步迭代器,使开发者可以方便地处理异步代码。我们通过示例代码比较了使用 forfor...offor awaitfor await...of 循环时的异同,并给出了正确的异步代码写法。

在实践中,我们需要特别注意异步代码的写法和语法规范,尤其需要慎重处理 Promise 对象的处理。通过掌握 for await...of 循环,我们可以更好地处理异步代码和迭代操作,提高代码的可维护性和安全性。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/652ce7857d4982a6ebe6ff81


纠错
反馈