【js】异步迭代器(async|【js】异步迭代器(async Iterator)

异步迭代器(async Iterator)

  1. 同步迭代器
  2. 异步迭代器
  3. for await...of
  4. 异步生成器函数
  5. yield*语句
1.同步迭代器
  • 普通的迭代器生成函数在被调用后会返回一个迭代器对象,可以去调用迭代器上的next方法
  • next方法一旦执行,就必须同步地得到一个状态对象,{value,done}
    //迭代器生成函数 function makeIterator(arr) { var nextIndex = 0; return { next() { return nextIndex < arr.length ? { value: arr[nextIndex++], done: false } : { value: undefined, done: true } } } } //调用并遍历 const arr = [1] let iter = makeIterator(arr) console.log(iter.next()) //{value: 1, done: false} console.log(iter.next()); //{value: undefined, done: true}

2.异步迭代器 让next返回的value是一个Promise对象,用then链式处理
//迭代器生成函数 function makeIterator(arr) { var nextIndex = 0; let delay = 4000 return { next() { let res = nextIndex < arr.length ? { value: new Promise(resolve => setTimeout(() => resolve(arr[nextIndex++]), delay -= 1000)), done: false } : { value: undefined, done: true } return res } } } //调用并遍历 const arr = [1, 2] let iter = makeIterator(arr) iter.next().value.then(val => console.log(val)) //1 iter.next().value.then(val => console.log(val)); //2 iter.next().value.then(val => console.log(val)); //undefined

这种方法只是让value异步执行,done的值并不是异步产生的,并且执行了流程不清晰,语义比较绕
next直接返回一个Promise,用then的链式处理异步
//迭代器生成函数 function asyncIterator(arr) { var nextIndex = 0 return { [Symbol.asyncIterator]() { return { next() { if (nextIndex < arr.length) { return new Promise(resolve => { setTimeout(() => resolve({ value: arr[nextIndex++], done: false }), 1000) }) } else { return { value: undefined, done: true } } } } } } } //链式执行 const asyncIterable = asyncIterator([1, 2]) const asyncIter = asyncIterable[Symbol.asyncIterator]() asyncIter .next() .then(val1 => { console.log(val1); return asyncIter.next() }) .then(val2 => { console.log(val2); return asyncIter.next() }) .then(val3 => { console.log(val3); })//{value: 1, done: false} //{value: 2, done: false} //{value: undefined, done: true}

既然asyncIter返回的是一个Promise,那么执行可以用async改写,能得到一致的结果
async function runner() { const asyncIterable = asyncIterator([1, 2]) const asyncIter = asyncIterable[Symbol.asyncIterator]() let val1 = await asyncIter.next() console.log(val1); console.log(await asyncIter.next()); console.log(await asyncIter.next()); }

3 for await...of 根据上面的迭代器生成函数,Symbol.asyncIterator是一个异步迭代器的接口,返回一个迭代器对象,可以用for await...of去遍历这个接口
async function runner() { for await (const i of asyncIterator([1, 2])) { console.log(i); } } runner() //1 //2

  • asyncIterator([1, 2])返回一个对象,这个对象拥有异步迭代器接口,能返回一个异步迭代器对象
  • 这个对象的异步迭代器的next方法被for...of循环自动调用会得到一个Promise 对象
  • await用来处理这个 Promise 对象,在resolve之后把得到的值i传入for...of的循环体
遍历出错会终止for await...of,并报错
可以将for await..of放在try中,用catch捕获错误
4.异步生成器函数 同步的生成器函数会生成一个同步迭代器,那么异步生成器则生成异步迭代器
作用
Generator 函数处理同步操作和异步操作时,能够使用同一套接口
特点
异步生成器函数就是async和Generator的结合
function promise(data, delay) { return new Promise(resolve => { setTimeout(() => { resolve(data) }, delay) }) } function printHello() { return promise("Hello", 1000) } function printWorld() { return promise("World", 1000) } async function* gene() { yield printHello() yield printWorld() } let iter = gene() iter.next() .then(val => { console.log(val); })//{value:"Hello",done:false}

  • 异步的生成器函数返回一个迭代器对象,调用next方法,返回的是一个Promise,用then能取到状态对象
  • 同步的生成器函数返回一个迭代器对象,调用next方法,直接返回状态对象,状态对象中的value是一个Promise
  • 使用for await...of可以异步的遍历同步迭代器,但是只有value是异步的,done的生成仍然是同步的
    async function runner() { for await (const i of iter) { console.log(i); } } runner()

    不管Generator函数前是否有async都会分别延迟1000ms打印Hello与World
await 和 yield可以同时出现在异步Generator函数中
async function* readLines(path) { let file = await fileOpen(path); try { while (!file.EOF) { yield await file.readLine(); } } finally { await file.close(); } }

await后面的操作返回一个Promise对象,将外部操作产生的值输入函数内部
yield命令会返回一个Promise,作为每个next暂停的位置,将函数内部的值输出
  • async函数和异步Generator函数都是对异步操作的封装
  • async函数自带执行器
  • 异步Generator函数可以用for await...of去遍历
【【js】异步迭代器(async|【js】异步迭代器(async Iterator)】函数就可以分为四类
  1. 普通函数
  2. async函数
  3. Generator函数
  4. 异步Generator函数
5. yield* 语句 yield* 后可以跟一个Generator函数,将其语句展开到异步生成器内
function* gene1() { yield 'a' yield 'b' console.log(0); } async function* gene2() { yield* gene1() yield 'c'; } async function runner() { for await (const i of gene2()) { console.log(i); } } runner() //"a" //"b" //0 //"c"

    推荐阅读