For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/proposal-async-iteration.md.
  • 简体中文
  • Asynchronous Iteration S4

    中文标题:异步迭代

    提案概览
    提案速览

    该提案引入了 AsyncIterator 接口、for-await-of 语句和异步生成器函数来处理异步数据源。它解决了同步迭代器在表示异步数据方面的局限性。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    JavaScript 的异步迭代器

    概述和动机

    迭代器接口(在 ECMAScript 2015 中引入)是一种顺序数据访问协议,它使得通用且可组合的数据消费者和转换器的开发成为可能。它们的主要接口是一个 next() 方法,该方法返回一个 { value, done } 元组,其中 done 是一个布尔值,指示是否已到达迭代器的末尾,而 value 是序列中产出的值。

    由于序列中的下一个值和数据源的“完成”状态都必须在迭代器方法返回时已知,因此迭代器仅适用于表示同步数据源。虽然 JavaScript 程序员遇到的许多数据源是同步的(例如内存中的列表和其他数据结构),但许多其他数据源则不是。例如,任何需要 I/O 访问的数据源通常都会使用基于事件或流式的异步 API 来表示。不幸的是,迭代器不能用于表示此类数据源。

    (即使是一个 promise 的迭代器也是不够的,因为它只允许异步确定值,但要求同步确定“完成”状态。)

    为了为异步数据源提供通用的数据访问协议,我们引入了 AsyncIterator 接口、异步迭代语句(for-await-of)以及异步生成器函数。

    异步迭代器和异步可迭代对象

    异步迭代器与迭代器非常相似,只是它的 next() 方法返回一个 { value, done } 对的 promise。如上所述,我们必须返回迭代器结果对的 promise,因为在迭代器方法返回时,迭代器的下一个值和“完成”状态都是未知的。

    const { value, done } = syncIterator.next();
    
    asyncIterator.next().then(({ value, done }) => /* ... */);

    此外,我们引入一个新的符号用于从给定对象获取异步迭代器,Symbol.asyncIterator。这允许任意对象声明它们是 async iterables,类似于 Symbol.iterator 允许你声明是普通的同步可迭代对象。一个可能使用此功能的类的例子是可读流

    异步迭代器概念中隐含着一个请求队列的概念。由于迭代器方法在先前请求的结果解决之前可以被多次调用,因此每个方法调用必须在内部排队,直到所有先前的请求操作完成。

    异步迭代语句:for-await-of

    我们引入了 for-of 迭代语句的一个变体,它遍历异步可迭代对象。一个示例用法是:

    for await (const line of readLines(filePath)) {
      console.log(line);
    }

    异步 for-of 语句只允许在异步函数和异步生成器函数中使用(后者见下文)。

    在执行期间,使用 [Symbol.asyncIterator]() 方法从数据源创建一个异步迭代器。

    每次我们访问序列中的下一个值时,我们隐式地 await 迭代器方法返回的 promise。

    异步生成器函数

    异步生成器函数类似于生成器函数,但有以下区别:

    • 被调用时,异步生成器函数返回一个对象,即一个 async generator,其方法(nextthrowreturn)返回 { value, done } 的 promise,而不是直接返回 { value, done }。这自动使得返回的异步生成器对象成为 async iterators
    • 允许使用 await 表达式和 for-await-of 语句。
    • yield* 的行为被修改为支持委托给异步可迭代对象。

    例如:

    async function* readLines(path) {
      let file = await fileOpen(path);
    
      try {
        while (!file.EOF) {
          yield await file.readLine();
        }
      } finally {
        await file.close();
      }
    }

    这个函数然后返回一个异步生成器对象,该对象可以使用前面示例中所示的 for-await-of 来消费。

    实现状态

    原生实现