前言
要看懂这篇请先看下面几篇
JavaScript – Generator Function
JavaScript – 用 Generator 运行异步函数 & await async
Async Iterator (es2018)
es6 推出的 Iterator + for...of 非常好用, 但是它只能执行同步代码. 不支持异步编程.
顾名思义 Async Iterator 就是 Iterator 的 Async 版本. 它支持异步编程.
我们来看看 sync 和 async Iterator 的对比
sync Iterable
const iterable: Iterable<string> = { [Symbol.iterator]() { let index = 0; return { next() { index++; if (index === 10) { return { done: true, value: '', }; } return { done: false, value: 'value' + index }; }, }; }, }; for (const value of iterable) { console.log('value', value); }
async Iterable
const asyncIterable: AsyncIterable<string> = { [Symbol.asyncIterator]() { let index = 0; return { async next() { return new Promise((resolve) => { setTimeout(() => { index++; if (index === 10) { resolve({ done: true, value: '', }); } return resolve({ done: false, value: 'value' + index }); }, 1000); }); }, }; }, }; (async () => { const asyncIterator = asyncIterable[Symbol.asyncIterator](); const { value, done } = await asyncIterator.next(); console.log([value, done]); for await (const value of asyncIterable) { console.log('value', value); } })();
和 sync iterable 的区别是
1. 属性是 Symbol.asyncIterator
2. iterator next 返回的是一个 promise, promise 的返回才是 done 和 value
3. 遍历的方式是 for await ... of
你可能会认为, sync iterable 也可以返回 promise 丫.
的确. 在 JavaScript – 用 Generator 运行异步函数 & await async 里有提到如何用 Generator + Iterator + Promise + 自执行 Generator 来实现异步编程 (async await 语法糖的背后的原理)
它的 iterator next value 返回的就是 promise. 但不要忘了, 还有 done 属性呢? 这个总不能返回 Promise 了丫. 所以还是有细微区别的.
Async Generator (es2018)
和 Async Iterator 一样概念. Generator 也有 Async 版本.
function delayAsync(time: number, value: string) { return new Promise((resolve) => { setTimeout(() => { resolve(value); }, time); }); } async function* myGenerator() { yield delayAsync(1000, 'a'); console.log('do something'); yield delayAsync(1000, 'b'); } (async () => { const asyncIterator = myGenerator(); for await (const value of asyncIterator) { console.log(value); } // 1000ms after log a // do something // another 1000ms after log b })();
和 sync Generator 的区别是
1. async function* 多了 async 关键字开头
2. yield 返回 Promise
3. 可以用 for await...of 遍历
for...of + Promise.all 对比 for await...of
当有一堆 promises 想 loop 的时候, 在 for await...of 出现前. 通常是搭配 Promise.all 来使用的
const promises = [delayAsync(1000, 'a'), delayAsync(2000, 'b')]; (async () => { for (const value of await Promise.all(promises)) { console.log(value); } for await (const value of promises) { console.log(value); } })();
几时知识点:
1. 当 delayAsync 调用时, setTimeout 马山就执行了. 所以下面这 2 个 timeout 是一起 start 的哦
const promises = [delayAsync(1000, 'a'), delayAsync(2000, 'b')];
2.
for (const value of await Promise.all(promises)) { console.log(value); }
await Promise.all 返回 array 后才进入 for...of. 所以在 2 秒钟后 log a 和 log b 会马上执行 (同步, 中间没有间隔时间)
3.
for await (const value of promises) { console.log(value); }
和 for...of 不同, 它会先去 loop, 所以会先拿出第一个 promise, 等待. 1 秒钟后就会执行 log a.
然后再拿第 2 个 promise. 这时 promise2 已经过去 1 秒了, 所以再 1 秒钟后就会只是 log b.
一定要搞清楚它们执行的顺序和时机哦.