什么是async迭代器?

随着异步数据源变得普遍(如分页API、数据库流、WebSocket消息),我们需要一种方式来顺序消费那些值不会立即就绪的序列。Async迭代器正是为解决此问题而生,它允许你使用for await...of循环来遍历异步产生的数据。

Async迭代器协议

一个对象要成为异步可迭代对象,它必须实现[Symbol.asyncIterator]方法。这个方法返回一个异步迭代器对象。异步迭代器与普通迭代器类似,但其next()方法返回一个Promise,该Promise解决后返回{ value, done }形式的迭代结果。

const asyncIterable = {
  [Symbol.asyncIterator]() {
    let count = 0;
    return {
      async next() {
        await new Promise(resolve => setTimeout(resolve, 100));
        if (count < 3) {
          return { value: count++, done: false };
        }
        return { done: true };
      }
    };
  }
};

在这个例子中,每次调用next()都会等待100毫秒后返回下一个值,模拟了异步数据的产生。

使用for await…of循环消费

for await...of循环是专门为异步可迭代对象设计的。它会自动处理异步迭代器返回的Promise,并在值可用时将其赋值给循环变量。

async function process() {
  for await (const value of asyncIterable) {
    console.log(value); // 依次输出 0, 1, 2,中间有间隔
  }
}
process();

循环会一直等待每次next()调用返回的Promise解决,直到遇到done: true。这使得异步数据的消费代码看起来和遍历同步数组一样直观。

使用异步生成器函数

手动实现[Symbol.asyncIterator]next()方法很繁琐。异步生成器函数为此提供了语法糖。在function关键字前加async,并在函数体内使用yield来产生值,这个函数就会自动返回一个异步可迭代对象。

async function* asyncGenerator() {
  for (let i = 0; i < 3; i++) {
    await new Promise(resolve => setTimeout(resolve, 100));
    yield i;
  }
}

async function run() {
  const asyncIterable = asyncGenerator(); // 调用生成器返回异步可迭代对象
  for await (const num of asyncIterable) {
    console.log(num); // 依次输出 0, 1, 2
  }
}
run();

异步生成器极大地简化了异步迭代器的创建。yield可以返回一个值,并且函数可以在yieldawait处暂停,等待异步操作完成。

实际应用场景

Async迭代器非常适合处理分页API。你可以创建一个异步生成器,在每次迭代中自动获取下一页数据。

async function* fetchPages(url) {
  let nextUrl = url;
  while (nextUrl) {
    const response = await fetch(nextUrl);
    const data = await response.json();
    yield data.items;
    nextUrl = data.nextPage; // 假设API响应中包含下一页链接
  }
}

// 像处理本地数组一样处理所有分页数据
for await (const pageItems of fetchPages('/api/items?page=1')) {
  for (const item of pageItems) {
    console.log(item);
  }
}

它们也常用于处理Node.js的Readable流(流在v10之后本身就是异步可迭代的)、WebSocket消息或任何需要按顺序异步消费的数据序列。Async迭代器将异步数据源抽象为统一的拉取模型,让异步数据流处理变得优雅而强大。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

    暂无评论内容