JavaScript中的异步生成器与异步迭代
字数 694 2025-11-22 11:40:18

JavaScript中的异步生成器与异步迭代

描述
异步生成器是ES2018引入的特性,它结合了生成器函数和异步函数的特点,允许你使用生成器语法来生成一系列异步产生的值。与异步迭代器协议配合使用,可以优雅地处理异步数据流,比如分页API、实时数据流等场景。

核心概念解析

  1. 异步生成器函数:使用async function*声明的函数,内部可以使用yield来产生值
  2. 异步迭代器:实现了[Symbol.asyncIterator]方法的对象
  3. 异步迭代:使用for await...of循环来消费异步生成的值

异步生成器函数的基本结构

async function* asyncGenerator() {
  yield await Promise.resolve(1);  // 产生异步值1
  yield await Promise.resolve(2);  // 产生异步值2
  yield await Promise.resolve(3);  // 产生异步值3
}

异步迭代的工作原理

  1. 调用异步生成器函数返回一个异步迭代器对象
  2. 异步迭代器的next()方法返回一个Promise
  3. 每个Promise解析后包含{value, done}对象

手动消费异步生成器

const asyncIter = asyncGenerator();

// 手动调用next()消费
asyncIter.next().then(result => {
  console.log(result); // {value: 1, done: false}
  return asyncIter.next();
}).then(result => {
  console.log(result); // {value: 2, done: false}
  return asyncIter.next();
}).then(result => {
  console.log(result); // {value: 3, done: false}
  return asyncIter.next();
}).then(result => {
  console.log(result); // {value: undefined, done: true}
});

使用for await...of简化消费

async function consumeAsyncGenerator() {
  for await (const value of asyncGenerator()) {
    console.log(value); // 依次输出: 1, 2, 3
  }
}

实际应用示例:分页数据获取

async function* paginatedFetcher(url) {
  let currentPage = 1;
  let hasMore = true;

  while (hasMore) {
    // 模拟异步API调用
    const response = await fetch(`${url}?page=${currentPage}`);
    const data = await response.json();
    
    yield data.items;  // 产生当前页的数据
    
    hasMore = data.hasMore;
    currentPage++;
  }
}

// 使用示例
async function processAllPages() {
  for await (const pageData of paginatedFetcher('/api/data')) {
    console.log('Processing page:', pageData);
    // 处理每一页的数据
  }
}

错误处理机制

async function* asyncGeneratorWithError() {
  try {
    yield await Promise.resolve(1);
    throw new Error('Something went wrong');
    yield await Promise.resolve(2); // 不会执行
  } catch (error) {
    yield `Error handled: ${error.message}`;
  }
}

// 消费时的错误处理
async function handleErrors() {
  try {
    for await (const value of asyncGeneratorWithError()) {
      console.log(value); // 1, "Error handled: Something went wrong"
    }
  } catch (error) {
    console.error('Outer error:', error);
  }
}

与普通生成器的关键区别

  1. 异步生成器的next()返回Promise,普通生成器返回普通对象
  2. 使用for await...of而不是for...of
  3. 可以在yield后面跟Promise或异步操作

实现自定义异步可迭代对象

class AsyncRange {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }

  async *[Symbol.asyncIterator]() {
    for (let i = this.start; i <= this.end; i++) {
      // 模拟异步延迟
      await new Promise(resolve => setTimeout(resolve, 100));
      yield i;
    }
  }
}

// 使用自定义异步可迭代对象
async function demo() {
  const asyncRange = new AsyncRange(1, 5);
  for await (const num of asyncRange) {
    console.log(num); // 每隔100ms输出一个数字
  }
}

性能考虑和最佳实践

  1. 使用breakreturn提前终止循环可以避免不必要的异步计算
  2. 注意错误传播机制,异步生成器内部的错误会通过Promise rejection传播
  3. 考虑使用try...finally进行资源清理

异步生成器为处理异步数据流提供了声明式的语法糖,让异步代码的编写更加直观和易于维护。

JavaScript中的异步生成器与异步迭代 描述 异步生成器是ES2018引入的特性,它结合了生成器函数和异步函数的特点,允许你使用生成器语法来生成一系列异步产生的值。与异步迭代器协议配合使用,可以优雅地处理异步数据流,比如分页API、实时数据流等场景。 核心概念解析 异步生成器函数:使用 async function* 声明的函数,内部可以使用 yield 来产生值 异步迭代器:实现了 [Symbol.asyncIterator] 方法的对象 异步迭代:使用 for await...of 循环来消费异步生成的值 异步生成器函数的基本结构 异步迭代的工作原理 调用异步生成器函数返回一个异步迭代器对象 异步迭代器的 next() 方法返回一个Promise 每个Promise解析后包含 {value, done} 对象 手动消费异步生成器 使用for await...of简化消费 实际应用示例:分页数据获取 错误处理机制 与普通生成器的关键区别 异步生成器的 next() 返回Promise,普通生成器返回普通对象 使用 for await...of 而不是 for...of 可以在 yield 后面跟Promise或异步操作 实现自定义异步可迭代对象 性能考虑和最佳实践 使用 break 或 return 提前终止循环可以避免不必要的异步计算 注意错误传播机制,异步生成器内部的错误会通过Promise rejection传播 考虑使用 try...finally 进行资源清理 异步生成器为处理异步数据流提供了声明式的语法糖,让异步代码的编写更加直观和易于维护。