如何将异步迭代器转换为数组?

Sam*_*Sam 21 javascript async-await

鉴于我有一个异步生成器:

async function* generateItems() {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

将所有结果迭代到数组中的最简单方法是什么?我尝试了以下方法:

// This does not work
const allItems = Array.from(generateItems());
Run Code Online (Sandbox Code Playgroud)
// This works but is verbose
const allItems = [];
for await (const item of generateItems()) {
    allItems.push(item);
}
Run Code Online (Sandbox Code Playgroud)

(我知道这在生产应用程序中可能是不好的做法,但它对于原型设计很方便。)

Joe*_*Joe 14

如果有人仍在寻找解决方案,从 ES22 开始,您可以使用新的Array.fromAsync()静态方法。

这将返回一个承诺,其履行值是一个新的 Array 实例。

ES 提案的示例:

async function* f() {
  for (let i = 0; i < 4; i++) yield i;
}

// Resolves to [0, 1, 2, 3].
await Array.fromAsync(f());
Run Code Online (Sandbox Code Playgroud)

*注意:目前浏览器兼容性不是很好......

参考文献: MDN TC39


mpe*_*pen 13

您的解决方案是我所知道的唯一解决方案。这是一个 TypeScript 函数:

async function gen2array<T>(gen: AsyncIterable<T>): Promise<T[]> {
    const out: T[] = []
    for await(const x of gen) {
        out.push(x)
    }
    return out
}
Run Code Online (Sandbox Code Playgroud)

TypeScript 游乐场

  • @mindplay.dk 我认为它适用于 `AsyncIterable` 但不适用于 `AsyncIterator`。我添加了一个 TS Playground 链接——这符合您的要求吗? (2认同)

小智 8

这是一个简单的函数,可以将异步迭代器转换为数组,而无需包含整个包。

async function toArray(asyncIterator){ 
    const arr=[]; 
    for await(const i of asyncIterator) arr.push(i); 
    return arr;
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你,惊讶地发现这不是一阶概念...... (5认同)

Sam*_*Sam -9

看起来async-iterator-to-arraynpm 库是这样做的:

安装

npm install --save async-iterator-to-array
Run Code Online (Sandbox Code Playgroud)

用法

const toArray = require('async-iterator-to-array')

async function * iterator (values) {
  for (let i = 0; i < values.length; i++) {
    yield values[i]
  }
}

const arr = await toArray(iterator([0, 1, 2, 3, 4]))

console.info(arr) // 0, 1, 2, 3, 4
Run Code Online (Sandbox Code Playgroud)

  • 请注意,引用的包在内部的执行方式与 OP 标记为“详细”的方式完全相同。想一想,你的项目中真的需要另一个依赖吗?... (48认同)
  • @1valdis 请注意,这个答案是由 OP 编写的。 (7认同)