icon
生成器与迭代器

生成器与迭代器

生成器(Generator)和迭代器(Iterator)是 ES6 引入的强大特性,用于创建可迭代对象和控制函数执行流程。

迭代器(Iterator)

迭代器是一个对象,实现了 Iterator 协议,包含 next() 方法。

const iterator = {
  values: [1, 2, 3],
  index: 0,
  next() {
    if (this.index < this.values.length) {
      return { value: this.values[this.index++], done: false };
    }
    return { done: true };
  }
};

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { done: true }

可迭代对象(Iterable)

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

const iterable = {
  values: [1, 2, 3],
  [Symbol.iterator]() {
    let index = 0;
    return {
      next: () => {
        if (index < this.values.length) {
          return { value: this.values[index++], done: false };
        }
        return { done: true };
      }
    };
  }
};

for (const value of iterable) {
  console.log(value); // 1, 2, 3
}

生成器函数(Generator Function)

使用 function* 定义生成器函数,使用 yield 暂停执行。

function* numberGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = numberGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }

yield 关键字

  1. 基本用法
function* generator() {
  yield 1;
  yield 2;
  return 3; // return 会结束生成器
}

const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: true }
  1. yield 委托*
function* generator1() {
  yield 1;
  yield 2;
}

function* generator2() {
  yield* generator1();
  yield 3;
}

const gen = generator2();
console.log([...gen]); // [1, 2, 3]
  1. 传递值给生成器
function* generator() {
  const x = yield 1;
  const y = yield x + 2;
  return y;
}

const gen = generator();
console.log(gen.next());    // { value: 1, done: false }
console.log(gen.next(10)); // { value: 12, done: false } (x = 10)
console.log(gen.next(20));  // { value: 20, done: true } (y = 20)

实际应用

  1. 无限序列
function* fibonacci() {
  let [prev, curr] = [0, 1];
  while (true) {
    yield curr;
    [prev, curr] = [curr, prev + curr];
  }
}

const fib = fibonacci();
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
console.log(fib.next().value); // 3
console.log(fib.next().value); // 5
  1. 遍历树结构
function* traverseTree(node) {
  yield node.value;
  if (node.left) {
    yield* traverseTree(node.left);
  }
  if (node.right) {
    yield* traverseTree(node.right);
  }
}

const tree = {
  value: 1,
  left: {
    value: 2,
    left: { value: 4 },
    right: { value: 5 }
  },
  right: {
    value: 3,
    left: { value: 6 },
    right: { value: 7 }
  }
};

for (const value of traverseTree(tree)) {
  console.log(value); // 1, 2, 4, 5, 3, 6, 7
}
  1. 异步流程控制
function* asyncGenerator() {
  const result1 = yield fetch('/api/data1');
  const data1 = yield result1.json();
  
  const result2 = yield fetch('/api/data2');
  const data2 = yield result2.json();
  
  return { data1, data2 };
}

// 执行器
function run(generator) {
  const gen = generator();
  
  function handle(result) {
    if (result.done) return Promise.resolve(result.value);
    
    return Promise.resolve(result.value)
      .then(res => handle(gen.next(res)))
      .catch(err => handle(gen.throw(err)));
  }
  
  return handle(gen.next());
}

run(asyncGenerator()).then(data => console.log(data));
  1. 状态机
function* stateMachine() {
  let state = 'idle';
  
  while (true) {
    const action = yield state;
    
    switch (state) {
      case 'idle':
        if (action === 'start') state = 'running';
        break;
      case 'running':
        if (action === 'stop') state = 'stopped';
        break;
      case 'stopped':
        if (action === 'reset') state = 'idle';
        break;
    }
  }
}

const machine = stateMachine();
console.log(machine.next().value);      // 'idle'
console.log(machine.next('start').value); // 'running'
console.log(machine.next('stop').value);  // 'stopped'
console.log(machine.next('reset').value); // 'idle'
  1. 数据流处理
function* dataProcessor() {
  let data = yield;
  
  while (true) {
    data = yield data * 2;
  }
}

const processor = dataProcessor();
processor.next(); // 启动生成器
console.log(processor.next(5).value);  // 10
console.log(processor.next(10).value); // 20
console.log(processor.next(15).value); // 30

生成器方法

  1. next(value)

    • 恢复生成器执行,传入的值作为 yield 表达式的值
  2. return(value)

    • 结束生成器,返回指定值
function* generator() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = generator();
console.log(gen.next());      // { value: 1, done: false }
console.log(gen.return(100)); // { value: 100, done: true }
console.log(gen.next());      // { value: undefined, done: true }
  1. throw(error)
    • 向生成器抛出错误
function* generator() {
  try {
    yield 1;
    yield 2;
  } catch (error) {
    console.log('Caught:', error);
    yield 3;
  }
}

const gen = generator();
console.log(gen.next());        // { value: 1, done: false }
console.log(gen.throw('error')); // Caught: error, { value: 3, done: false }

内置可迭代对象

数组、字符串、Map、Set 等都是可迭代的:

// 数组
for (const item of [1, 2, 3]) {
  console.log(item);
}

// 字符串
for (const char of 'hello') {
  console.log(char);
}

// Map
const map = new Map([['a', 1], ['b', 2]]);
for (const [key, value] of map) {
  console.log(key, value);
}

// Set
const set = new Set([1, 2, 3]);
for (const value of set) {
  console.log(value);
}

自定义可迭代对象

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

  *[Symbol.iterator]() {
    for (let i = this.start; i <= this.end; i++) {
      yield i;
    }
  }
}

const range = new Range(1, 5);
console.log([...range]); // [1, 2, 3, 4, 5]

迭代器协议

// 实现迭代器协议
const myIterable = {
  [Symbol.iterator]() {
    let step = 0;
    return {
      next() {
        step++;
        if (step === 1) {
          return { value: 'hello', done: false };
        } else if (step === 2) {
          return { value: 'world', done: false };
        }
        return { done: true };
      }
    };
  }
};

for (const value of myIterable) {
  console.log(value); // 'hello', 'world'
}

注意事项

  1. 生成器函数调用返回生成器对象
function* gen() {
  yield 1;
}

const g = gen(); // 返回生成器对象,不执行函数体
console.log(g.next()); // 执行并返回 { value: 1, done: false }
  1. 生成器只能迭代一次
function* gen() {
  yield 1;
  yield 2;
}

const g = gen();
console.log([...g]); // [1, 2]
console.log([...g]); // [] (已耗尽)
  1. yield 只能在生成器函数中使用
function normal() {
  yield 1; // SyntaxError: Unexpected strict mode reserved word
}
  1. 生成器是惰性的
function* gen() {
  console.log('Started');
  yield 1;
  console.log('Ended');
}

const g = gen(); // 不输出任何内容
g.next();        // 输出: Started
g.next();        // 输出: Ended

与 async/await 的关系

async/await 基于生成器和 Promise:

// async/await (语法糖)
async function fetchData() {
  const data = await fetch('/api/data');
  return data.json();
}

// 使用生成器实现类似功能
function* fetchDataGen() {
  const data = yield fetch('/api/data');
  return data.json();
}