ES6具有返回迭代器的生成器:
function* range(n) { for (let i = 0; i < n; ++i) { yield i; } } for (let x of range(10)) { console.log(x); }
有一个异步函数的提议,它返回Promises:
async function f(x) { let y = await g(x); return y * y; } f(2).then(y => { console.log(y); });
那么如果我将两者结合起来会发生什么,就像这样:
async function* ag(n) { for (let i = 0; i < n; ++i) { yield i; } }
它返回了什么?是Promise
吗?Iterator
?别的什么?我该如何食用?我想应该有一个相应的for
循环,什么会异步迭代它的结果,如:
for (await let x of ag(10)) { console.log(x); }
在尝试访问下一个项目之前等待每个项目可用.
Promise>
还是Iterator>
?
都不是.它仍未获得批准,但当前的实现还会返回其他内容.Kris Kowal 撰写了一篇关于异步生成器的文章,并参考了Jafar Husain的AsyncGenerator对ES7的提议.编辑:我们有tc39提案和babel支持!
让我们定义一些类型(简化):
interface Iterator{ Iteration next(); } type Iteration = { done: boolean, value: T }
我们正在寻找可以像这样使用的东西:
for (;;) { var iteration = await async_iterator.next(); if (iteration.done) { return iteration.value; } else { console.log(iteration.value); } }
An Iterator
生成同步迭代,其值为Promises.它可以像这样使用:
for (;;) { var iteration = iterator_promise.next(); if (iteration.done) { return await iteration.value; } else { console.log(await iteration.value); } }
A Promise
只是一个常规的同步迭代器,从未来开始:
var iterator = await promise_iterator; for (;;) { var iteration = iterator.next(); if (iteration.done) { return iteration.value; } else { console.log(iteration.value); } }
所以既不合适Iterator
也Promise
不合适.目前异步生成器返回AsyncIterator
s:
interface AsyncIterator{ Promise > next(); }
这完全有道理.移动到迭代器的下一个元素是异步操作,这可以完全按照我们想要的方式使用.
如何使用异步生成器?Babeljs.io已经编译了异步生成器.Babeljs.io/repl示例:
编辑:babeljs.io没有预设编译异步生成器,因为babel 6,babel-plugin-transform-regenerator
支持{asyncGenerators:true}
选项.
编辑:看看transform-async-generator-functions
babel 6插件.
function delay(timeout, val) { return new Promise(resolve => setTimeout(resolve, timeout, val)); } async function* asyncGenerator() { for (var i = 0; i < 5; i++) { await delay(500); yield i; } } async function forAwait(iter, fn) { for (;;) { let iteration = await iter.next(); if (iteration.done) return iteration.value; await fn(iteration.value); } } async function main() { console.log('Started'); await forAwait(asyncGenerator(), async item => { await delay(100); console.log(item); }); console.log('End'); } main();
有一个方便的for await
循环用于异步迭代器的建议(在Async迭代中描述):
for await (let line of readLines(filePath)) { print(line); }
更新:
不幸的是,async-await
没有成为ECMAScript 2016的一部分.至少await
提到了一个保留字以供将来使用.
更新:
相关提案:
https://tc39.github.io/ecmascript-asyncawait/
https://github.com/tc39/proposal-async-iteration