// File: main.js const createAsyncGenerator = async function*(){ yield await new Promise((r) => r('a')) yield 'b' yield 'c' } const main = async () => { const asyncGenerator = createAsyncGenerator() let result = {done:false} while(!result.done) { result = await asyncGenerator.next() if(result.done) { continue; } console.log(result.value) } } main()
但是,这不是最直接的循环机制。我既不喜欢 while 的循环条件,也不想手动检查 result.done。另外, result.done 变量必须同时存在于内部和外部块的作用域内。
幸运的是大多数(也许是所有?)支持异步迭代器的 javascript 实现也都支持特殊的 for await ... of 循环语法。例如:
const createAsyncGenerator = async function*(){ yield await new Promise((r) => r('a')) yield 'b' yield 'c' } const main = async () => { const asyncGenerator = createAsyncGenerator() for await(const item of asyncGenerator) { console.log(item) } } main()
如果运行上述代码,则会看到异步生成器与可迭代对象已被成功循环,并且在循环体中得到了 Promise 的完全解析值。
$ node main.js
a
b
c
这个 for await ... of 循环更喜欢实现了异步迭代器协议的对象。但是你可以用它遍历任何一种可迭代对象。
for await(const item of [1,2,3]) { console.log(item) }
当你使用 for await 时,Node.js 将会首先在对象上寻找 Symbol.asyncIterator 方法。如果找不到,它将回退到使用 Symbol.iterator 的方法。
非线性代码执行与 await 一样,for await 循环会将非线性代码执行引入程序中。也就是说,你的代码将会以和编写的代码不同的顺序运行。
当你的程序第一次遇到 for await 循环时,它将在你的对象上调用 next。
该对象将 yield 一个 promise,然后代码的执行将会离开你的 async 函数,并且你的程序将继续在该函数之外执行。
一旦你的 promise 得到解决,代码执行将会使用这个值返回到循环体。
当循环结束并进行下一个行程时,Node.js 将在对象上调用 next。该调用会产生另一个 promise,代码执行将会再次离开你的函数。重复这种模式,直到 Promise 解析为 done 为 true 的对象,然后在 for await 循环之后继续执行代码。
下面的例子可以说明一点:
let count = 0 const getCount = () => { count++ return `${count}. ` } const createAsyncGenerator = async function*() { console.log(getCount() + 'entering createAsyncGenerator') console.log(getCount() + 'about to yield a') yield await new Promise((r)=>r('a')) console.log(getCount() + 're-entering createAsyncGenerator') console.log(getCount() + 'about to yield b') yield 'b' console.log(getCount() + 're-entering createAsyncGenerator') console.log(getCount() + 'about to yield c') yield 'c' console.log(getCount() + 're-entering createAsyncGenerator') console.log(getCount() + 'exiting createAsyncGenerator') } const main = async () => { console.log(getCount() + 'entering main') const asyncGenerator = createAsyncGenerator() console.log(getCount() + 'starting for await loop') for await(const item of asyncGenerator) { console.log(getCount() + 'entering for await loop') console.log(getCount() + item) console.log(getCount() + 'exiting for await loop') } console.log(getCount() + 'done with for await loop') console.log(getCount() + 'leaving main') } console.log(getCount() + 'before calling main') main() console.log(getCount() + 'after calling main')
这段代码你用了编号的日志记录语句,可让你跟踪其执行情况。作为练习,你需要自己运行程序然后查看执行结果是怎样的。
如果你不知道它的工作方式,就会使程序的执行产生混乱,但异步迭代的确是一项强大的技术。
总结到此这篇关于Node.js中异步生成器与异步迭代的文章就介绍到这了,更多相关Node.js异步生成器与异步迭代内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!