Skip to content

异步迭代器与生成器

迭代器(Iterator)

迭代器的概念

迭代器是一个对象,它提供了一个 next() 方法,用于遍历集合中的元素。每次调用 next() 方法都会返回一个包含 valuedone 属性的对象。

迭代器的实现

javascript
// 自定义迭代器
function createIterator(items) {
  let index = 0;
  return {
    next() {
      return index < items.length
        ? { value: items[index++], done: false }
        : { value: undefined, done: true };
    }
  };
}

// 使用迭代器
const iterator = createIterator(['a', 'b', 'c']);
console.log(iterator.next()); // { value: 'a', done: false }
console.log(iterator.next()); // { value: 'b', done: false }
console.log(iterator.next()); // { value: 'c', done: false }
console.log(iterator.next()); // { value: undefined, done: true }

可迭代对象(Iterable)

可迭代对象的概念

可迭代对象是实现了 Symbol.iterator 方法的对象,该方法返回一个迭代器。

常见的可迭代对象

  • 数组(Array)
  • 字符串(String)
  • 集合(Set)
  • 映射(Map)
  • arguments 对象
  • NodeList 对象

自定义可迭代对象

javascript
// 自定义可迭代对象
const customIterable = {
  items: ['a', 'b', 'c'],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        return index < this.items.length
          ? { value: this.items[index++], done: false }
          : { value: undefined, done: true };
      }
    };
  }
};

// 使用 for...of 循环遍历
for (const item of customIterable) {
  console.log(item); // 输出: a, b, c
}

生成器(Generator)

生成器的概念

生成器是一种特殊的函数,它可以暂停执行并在稍后继续执行。生成器函数使用 function* 语法定义,使用 yield 关键字暂停执行。

生成器的基本使用

javascript
// 生成器函数
function* generatorFunction() {
  yield 'Hello';
  yield 'World';
  return 'End';
}

// 创建生成器对象
const generator = generatorFunction();

console.log(generator.next()); // { value: 'Hello', done: false }
console.log(generator.next()); // { value: 'World', done: false }
console.log(generator.next()); // { value: 'End', done: true }

生成器的特点

  1. 惰性求值:生成器函数在调用 next() 方法时才会执行
  2. 状态保存:生成器会保存函数的执行状态
  3. 可迭代:生成器对象是可迭代的,可以使用 for...of 循环遍历
  4. 双向通信:可以通过 next() 方法向生成器传递值

生成器与迭代器的关系

生成器函数返回的生成器对象既是迭代器,也是可迭代对象。

javascript
function* generatorFunction() {
  yield 1;
  yield 2;
  yield 3;
}

const generator = generatorFunction();

// 作为迭代器使用
console.log(generator.next()); // { value: 1, done: false }

// 作为可迭代对象使用
for (const value of generatorFunction()) {
  console.log(value); // 输出: 1, 2, 3
}

异步迭代器(Async Iterator)

异步迭代器的概念

异步迭代器是一个对象,它提供了一个 next() 方法,该方法返回一个 Promise,解析为包含 valuedone 属性的对象。

异步迭代器的实现

javascript
// 自定义异步迭代器
function createAsyncIterator(items) {
  let index = 0;
  return {
    next() {
      return Promise.resolve()
        .then(() => {
          return index < items.length
            ? { value: items[index++], done: false }
            : { value: undefined, done: true };
        });
    }
  };
}

// 使用异步迭代器
const asyncIterator = createAsyncIterator(['a', 'b', 'c']);
asyncIterator.next()
  .then(result => console.log(result)); // { value: 'a', done: false }
asyncIterator.next()
  .then(result => console.log(result)); // { value: 'b', done: false }
asyncIterator.next()
  .then(result => console.log(result)); // { value: 'c', done: false }
asyncIterator.next()
  .then(result => console.log(result)); // { value: undefined, done: true }

异步可迭代对象(Async Iterable)

异步可迭代对象的概念

异步可迭代对象是实现了 Symbol.asyncIterator 方法的对象,该方法返回一个异步迭代器。

自定义异步可迭代对象

javascript
// 自定义异步可迭代对象
const asyncIterable = {
  items: ['a', 'b', 'c'],
  [Symbol.asyncIterator]() {
    let index = 0;
    return {
      next: () => {
        return Promise.resolve()
          .then(() => {
            return index < this.items.length
              ? { value: this.items[index++], done: false }
              : { value: undefined, done: true };
          });
      }
    };
  }
};

// 使用 for await...of 循环遍历
async function iterateAsync() {
  for await (const item of asyncIterable) {
    console.log(item); // 输出: a, b, c
  }
}

iterateAsync();

异步生成器(Async Generator)

异步生成器的概念

异步生成器是一种特殊的生成器函数,它可以使用 await 关键字,返回一个异步生成器对象。异步生成器函数使用 async function* 语法定义。

异步生成器的基本使用

javascript
// 异步生成器函数
async function* asyncGeneratorFunction() {
  yield 'Hello';
  await new Promise(resolve => setTimeout(resolve, 1000));
  yield 'World';
  return 'End';
}

// 创建异步生成器对象
const asyncGenerator = asyncGeneratorFunction();

// 使用异步生成器
asyncGenerator.next()
  .then(result => console.log(result)); // { value: 'Hello', done: false }
asyncGenerator.next()
  .then(result => console.log(result)); // { value: 'World', done: false }
asyncGenerator.next()
  .then(result => console.log(result)); // { value: 'End', done: true }

// 使用 for await...of 循环遍历
async function iterateAsyncGenerator() {
  for await (const value of asyncGeneratorFunction()) {
    console.log(value); // 输出: Hello, World
  }
}

iterateAsyncGenerator();

实际应用场景

1. 处理异步数据流

javascript
// 从 API 分批获取数据
async function* fetchDataInBatches(url, batchSize) {
  let page = 1;
  while (true) {
    const response = await fetch(`${url}?page=${page}&size=${batchSize}`);
    const data = await response.json();
    if (data.length === 0) {
      return;
    }
    yield data;
    page++;
  }
}

// 使用异步生成器
async function processData() {
  for await (const batch of fetchDataInBatches('https://api.example.com/data', 10)) {
    console.log(`Processing batch of ${batch.length} items`);
    // 处理数据...
  }
}

processData();

2. 处理文件流

javascript
// 读取大文件
const fs = require('fs');
const { Readable } = require('stream');

async function* readFileInChunks(filePath, chunkSize) {
  const stream = fs.createReadStream(filePath, { highWaterMark: chunkSize });
  for await (const chunk of stream) {
    yield chunk;
  }
}

// 使用异步生成器
async function processFile() {
  for await (const chunk of readFileInChunks('large-file.txt', 1024)) {
    console.log(`Processing chunk of ${chunk.length} bytes`);
    // 处理数据...
  }
}

processFile();

3. 实现异步迭代器接口

javascript
// 实现异步迭代器接口的类
class AsyncRange {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }

  [Symbol.asyncIterator]() {
    let current = this.start;
    return {
      next: async () => {
        await new Promise(resolve => setTimeout(resolve, 100)); // 模拟异步操作
        if (current < this.end) {
          return { value: current++, done: false };
        } else {
          return { value: undefined, done: true };
        }
      }
    };
  }
}

// 使用异步迭代器
async function iterateRange() {
  for await (const value of new AsyncRange(1, 5)) {
    console.log(value); // 输出: 1, 2, 3, 4
  }
}

iterateRange();

异步迭代器与生成器的优势

  1. 简化异步代码:使用 for await...of 循环可以使异步代码更简洁易读
  2. 惰性求值:只在需要时才获取数据,节省内存
  3. 可组合性:可以轻松组合多个异步操作
  4. 错误处理:可以使用 try-catch 处理异步迭代过程中的错误

错误处理

生成器中的错误处理

javascript
function* generatorWithError() {
  try {
    yield 'Hello';
    throw new Error('Generator error');
    yield 'World'; // 不会执行
  } catch (error) {
    yield `Caught error: ${error.message}`;
  }
}

const generator = generatorWithError();
console.log(generator.next()); // { value: 'Hello', done: false }
console.log(generator.next()); // { value: 'Caught error: Generator error', done: false }
console.log(generator.next()); // { value: undefined, done: true }

// 从外部抛出错误
generator.throw(new Error('External error'));

异步生成器中的错误处理

javascript
async function* asyncGeneratorWithError() {
  try {
    yield 'Hello';
    await new Promise((resolve, reject) => setTimeout(() => reject(new Error('Async error')), 1000));
    yield 'World'; // 不会执行
  } catch (error) {
    yield `Caught error: ${error.message}`;
  }
}

async function iterateAsyncGenerator() {
  try {
    for await (const value of asyncGeneratorWithError()) {
      console.log(value); // 输出: Hello, Caught error: Async error
    }
  } catch (error) {
    console.error('Outer error:', error);
  }
}

iterateAsyncGenerator();

总结

  • 迭代器:提供 next() 方法,用于遍历集合中的元素
  • 可迭代对象:实现了 Symbol.iterator 方法的对象
  • 生成器:使用 function* 定义的函数,可以暂停和恢复执行
  • 异步迭代器:提供返回 Promise 的 next() 方法
  • 异步可迭代对象:实现了 Symbol.asyncIterator 方法的对象
  • 异步生成器:使用 async function* 定义的函数,可以使用 await 关键字

异步迭代器与生成器是 JavaScript 中处理异步操作的强大工具,它们可以使异步代码更简洁、更易读,并且提供了一种统一的方式来处理同步和异步数据流。