HLJ 发布于
2025-06-11 11:09:37
0阅读

JavaScript Generator 函数详解

JavaScript Generator 详解

Generator(生成器)是 ES6 引入的一种特殊的函数,可以暂停和恢复执行,是 JavaScript 中实现协程的一种方式。

基本概念

定义 Generator 函数

Generator 函数使用 function* 语法定义:

function* generatorFunction() {
  yield 'Hello';
  yield 'World';
}

调用 Generator 函数

调用 Generator 函数不会立即执行函数体,而是返回一个 Generator 对象:

const generator = generatorFunction();

使用 Generator 对象

Generator 对象遵循迭代器协议,可以使用 next() 方法获取值:

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

yield 关键字

yield 是 Generator 函数的核心特性:

  1. 遇到 yield 表达式时,函数执行暂停
  2. 下次调用 next() 时,从暂停处继续执行
  3. yield 后面的表达式会被求值并作为 next() 返回对象的 value 属性

yield 与 next 的交互

可以向 next() 传递参数,这个参数会成为上一个 yield 表达式的返回值:

function* gen() {
  const x = yield 'Hello';
  const y = yield x + ' World';
  return y;
}

const g = gen();
console.log(g.next());    // { value: 'Hello', done: false }
console.log(g.next(42));  // { value: '42 World', done: false }
console.log(g.next(100)); // { value: 100, done: true }

Generator 方法

return()

终止 Generator 执行:

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

const g = gen();
console.log(g.next());       // { value: 1, done: false }
console.log(g.return('foo')); // { value: 'foo', done: true }
console.log(g.next());       // { value: undefined, done: true }

throw()

在 Generator 内部抛出错误:

function* gen() {
  try {
    yield 1;
    yield 2;
  } catch (e) {
    console.log('Error caught:', e);
  }
}

const g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.throw(new Error('Something went wrong')));
// Error caught: Error: Something went wrong
// { value: undefined, done: true }

应用场景

1. 实现迭代器

Generator 可以简化迭代器的实现:

function* range(start, end) {
  for (let i = start; i <= end; i++) {
    yield i;
  }
}

for (const num of range(1, 5)) {
  console.log(num); // 1, 2, 3, 4, 5
}

2. 异步编程

Generator 可以用来管理异步流程(通常与 Promise 配合使用):

function* asyncGenerator() {
  const result1 = yield fetch('https://api.example.com/data1');
  const result2 = yield fetch('https://api.example.com/data2');
  return [result1, result2];
}

// 需要一个执行器来运行这个生成器
async function runGenerator(generator) {
  const iterator = generator();
  let result;
  try {
    while (true) {
      const { value, done } = iterator.next(result);
      if (done) return value;
      result = await value;
    }
  } catch (err) {
    iterator.throw(err);
  }
}

runGenerator(asyncGenerator).then(console.log);

3. 无限序列

Generator 可以表示无限序列:

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
// 可以无限继续...

4. 状态管理

Generator 可以用于管理复杂的状态机:

function* trafficLight() {
  while (true) {
    yield 'red';
    yield 'yellow';
    yield 'green';
    yield 'yellow';
  }
}

const light = trafficLight();
console.log(light.next().value); // 'red'
console.log(light.next().value); // 'yellow'
console.log(light.next().value); // 'green'
// 可以无限循环...

yield* 表达式

yield* 用于委托给另一个 Generator 或可迭代对象:

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

function* generator2() {
  yield 1;
  yield* generator1();
  yield 4;
}

const gen = generator2();
console.log([...gen]); // [1, 2, 3, 4]

也可以委托给数组、字符串等可迭代对象:

function* gen() {
  yield* [1, 2, 3];
  yield* 'hello';
}

console.log([...gen()]); // [1, 2, 3, 'h', 'e', 'l', 'l', 'o']

注意事项

  1. Generator 函数执行后返回的是 Generator 对象,不是函数返回值
  2. 每次调用 Generator 函数都会返回一个新的 Generator 对象
  3. Generator 对象只能遍历一次
  4. 在箭头函数中不能使用 yield,会报错
  5. Generator 不能与 new 一起使用

Generator 为 JavaScript 带来了更强大的控制流程能力,特别是在处理异步操作和复杂迭代时提供了更优雅的解决方案。虽然现代 JavaScript 中 async/await 已经很大程度上取代了 Generator 在异步编程中的角色,但 Generator 仍然在许多场景下非常有用。

当前文章内容为原创转载请注明出处:http://www.good1230.com/detail/2025-06-11/836.html
最后生成于 2025-06-13 20:53:51
此内容有帮助 ?
0