在 JavaScript 中,异步编程一直是一个重要的话题。随着 ECMAScript 2017 的发布,异步迭代器和 for await...of 循环成为了 JavaScript 异步编程的新工具。本文将介绍异步迭代器和 for await...of 循环的概念、用法和应用场景,并提供示例代码和指导意义。
异步迭代器
异步迭代器是一种特殊的迭代器,它可以在异步操作完成后返回下一个值。在 JavaScript 中,异步迭代器是通过实现 Symbol.asyncIterator 方法来创建的。这个方法返回一个异步迭代器对象,对象上有一个 next 方法,调用 next 方法会返回一个 Promise 对象,Promise 对象的值是一个包含 value 和 done 属性的对象,表示异步迭代器的下一个值和是否迭代完成。
下面是一个简单的异步迭代器示例,它每隔一秒钟返回一个随机数:
// javascriptcn.com 代码示例 const asyncIterable = { [Symbol.asyncIterator]() { return { i: 0, next() { return new Promise(resolve => setTimeout(() => { this.i++; resolve({ value: Math.random(), done: false }); }, 1000)); } }; } }; (async function() { for await (const value of asyncIterable) { console.log(value); if (value > 0.9) { break; } } })();
在上面的示例中,我们先定义了一个包含 Symbol.asyncIterator 方法的对象 asyncIterable,这个方法返回一个包含 next 方法的异步迭代器对象。在 next 方法中,我们使用 setTimeout 模拟异步操作,并返回一个 Promise 对象,Promise 对象的值是一个包含随机数的对象。在主函数中,我们使用 for await...of 循环来迭代异步迭代器 asyncIterable,每隔一秒钟打印一个随机数,如果随机数大于 0.9,就跳出循环。
for await...of 循环
for await...of 循环是一个用于异步迭代器的循环语句,它可以遍历异步迭代器返回的结果,并在异步操作完成后执行相应的操作。for await...of 循环是 ECMAScript 2017 新增的语法,它的语法结构类似于 for...of 循环,只是在前面加了一个 await 关键字。
下面是一个使用 for await...of 循环遍历异步迭代器的示例:
// javascriptcn.com 代码示例 async function asyncFunc() { const asyncIterable = { [Symbol.asyncIterator]() { return { i: 0, next() { return new Promise(resolve => setTimeout(() => { this.i++; resolve({ value: Math.random(), done: this.i > 5 }); }, 1000)); } }; } }; for await (const value of asyncIterable) { console.log(value); } } asyncFunc();
在上面的示例中,我们定义了一个异步函数 asyncFunc,函数中定义了一个异步迭代器 asyncIterable,它每隔一秒钟返回一个随机数,最多返回 5 个随机数。在函数中使用 for await...of 循环遍历异步迭代器 asyncIterable,打印每个随机数。
应用场景
异步迭代器和 for await...of 循环的出现,为异步编程提供了更多的可能性和灵活性。下面是一些常见的应用场景:
1. 处理异步操作返回的结果
异步迭代器和 for await...of 循环可以用于处理异步操作返回的结果。在异步操作完成后,异步迭代器会返回下一个值,for await...of 循环会遍历异步迭代器返回的结果,并执行相应的操作。
// javascriptcn.com 代码示例 async function fetchData() { const asyncIterable = { [Symbol.asyncIterator]() { return { i: 0, next() { return fetch(`https://jsonplaceholder.typicode.com/todos/${this.i++}`).then(response => ({ value: response.json(), done: this.i > 10 })); } }; } }; for await (const value of asyncIterable) { console.log(value); } } fetchData();
在上面的示例中,我们定义了一个异步函数 fetchData,函数中定义了一个异步迭代器 asyncIterable,它每次返回一个 Promise 对象,Promise 对象的值是一个 JSON 数据。在函数中使用 for await...of 循环遍历异步迭代器 asyncIterable,打印每个 JSON 数据。
2. 处理多个异步操作的结果
异步迭代器和 for await...of 循环可以用于处理多个异步操作的结果。在异步操作完成后,异步迭代器会返回下一个值,for await...of 循环会遍历异步迭代器返回的结果,并执行相应的操作。
// javascriptcn.com 代码示例 async function fetchData() { const asyncIterable = { [Symbol.asyncIterator]() { return { i: 0, next() { return fetch(`https://jsonplaceholder.typicode.com/todos/${this.i++}`).then(response => ({ value: response.json(), done: this.i > 10 })); } }; } }; const results = []; for await (const value of asyncIterable) { results.push(value); } console.log(results); } fetchData();
在上面的示例中,我们定义了一个异步函数 fetchData,函数中定义了一个异步迭代器 asyncIterable,它每次返回一个 Promise 对象,Promise 对象的值是一个 JSON 数据。在函数中使用 for await...of 循环遍历异步迭代器 asyncIterable,将每个 JSON 数据添加到一个数组 results 中,并打印数组 results。
3. 处理流式数据
异步迭代器和 for await...of 循环可以用于处理流式数据,例如处理网络流、文件流等。在异步操作完成后,异步迭代器会返回下一个值,for await...of 循环会遍历异步迭代器返回的结果,并执行相应的操作。
// javascriptcn.com 代码示例 const { createReadStream } = require('fs'); const { createInterface } = require('readline'); async function readStream() { const asyncIterable = { [Symbol.asyncIterator]() { const rl = createInterface({ input: createReadStream('file.txt') }); return { async next() { const line = await new Promise(resolve => rl.once('line', resolve)); return { value: line, done: line === undefined }; } }; } }; for await (const value of asyncIterable) { console.log(value); } } readStream();
在上面的示例中,我们使用 Node.js 的 fs 模块和 readline 模块来读取文件流。在函数中定义了一个异步迭代器 asyncIterable,它每次返回一个 Promise 对象,Promise 对象的值是文件流的一行数据。在函数中使用 for await...of 循环遍历异步迭代器 asyncIterable,打印每行数据。
总结
异步迭代器和 for await...of 循环是 ECMAScript 2017 新增的语法,它们可以用于处理异步操作返回的结果、处理多个异步操作的结果、处理流式数据等场景。通过本文的介绍和示例代码,我们可以更好地理解异步迭代器和 for await...of 循环的概念、用法和应用场景,并且可以更好地掌握 JavaScript 异步编程的技巧和方法。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6506d9e795b1f8cacd27c785