跳转到内容

JavaScript生成器

来自代码酷

JavaScript生成器[编辑 | 编辑源代码]

JavaScript生成器(Generators)是ES6引入的一种特殊函数,它允许通过控制函数的执行流程来生成一系列值。与普通函数不同,生成器可以暂停和恢复执行,这使得它们非常适合处理异步操作、惰性求值和迭代大型数据集。

基本概念[编辑 | 编辑源代码]

生成器函数使用function*语法定义,并通过yield关键字暂停执行并返回一个值。调用生成器函数不会立即执行函数体,而是返回一个生成器对象,该对象遵循迭代器协议(Iterator Protocol),可以通过next()方法逐步执行。

语法示例[编辑 | 编辑源代码]

function* simpleGenerator() {
    yield 'First value';
    yield 'Second value';
    return 'Final value';
}

const generator = simpleGenerator();
console.log(generator.next()); // { value: 'First value', done: false }
console.log(generator.next()); // { value: 'Second value', done: false }
console.log(generator.next()); // { value: 'Final value', done: true }

关键特性[编辑 | 编辑源代码]

  • 暂停与恢复:生成器可以在执行过程中暂停(通过yield)并在之后恢复。
  • 惰性求值:值仅在请求时生成,适用于处理无限序列或大型数据流。
  • 双向通信:可以通过next(value)向生成器传递参数。

工作原理[编辑 | 编辑源代码]

生成器通过维护其执行上下文(包括局部变量和指令指针)来实现暂停和恢复。每次调用next()时,生成器从上次暂停的位置继续执行,直到遇到下一个yieldreturn

状态图[编辑 | 编辑源代码]

stateDiagram-v2 [*] --> Created Created --> Yielding: next() Yielding --> Yielding: next() Yielding --> Completed: return Completed --> [*]

实际应用[编辑 | 编辑源代码]

1. 生成无限序列[编辑 | 编辑源代码]

生成器非常适合表示无限序列(如斐波那契数列),因为值是按需计算的:

function* fibonacci() {
    let [a, b] = [0, 1];
    while (true) {
        yield a;
        [a, b] = [b, a + b];
    }
}

const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2

2. 异步流程控制[编辑 | 编辑源代码]

生成器可用于简化异步代码(常与Promise结合):

function* asyncGenerator() {
    const result = yield fetch('https://api.example.com/data');
    console.log(result);
}

function runAsync(generator) {
    const iterator = generator();
    function handleNext(iteratorResult) {
        if (iteratorResult.done) return;
        iteratorResult.value
            .then(res => res.json())
            .then(data => handleNext(iterator.next(data)));
    }
    handleNext(iterator.next());
}

runAsync(asyncGenerator);

3. 实现自定义迭代器[编辑 | 编辑源代码]

生成器简化了迭代器模式的实现:

const obj = {
    *[Symbol.iterator]() {
        yield 1;
        yield 2;
        yield 3;
    }
};

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

高级特性[编辑 | 编辑源代码]

yield* 委托[编辑 | 编辑源代码]

yield*允许生成器委托给另一个可迭代对象:

function* generatorA() {
    yield 'A1';
    yield 'A2';
}

function* generatorB() {
    yield 'B1';
    yield* generatorA();
    yield 'B2';
}

console.log([...generatorB()]); // ['B1', 'A1', 'A2', 'B2']

错误处理[编辑 | 编辑源代码]

可以通过throw()方法向生成器抛出错误:

function* errorHandling() {
    try {
        yield 'Normal';
    } catch (e) {
        yield `Caught: ${e}`;
    }
}

const gen = errorHandling();
console.log(gen.next()); // { value: 'Normal', done: false }
console.log(gen.throw('Error!')); // { value: 'Caught: Error!', done: false }

数学表达[编辑 | 编辑源代码]

生成器的暂停/恢复行为可以用状态机表示。设生成器的状态为Sn,则: Sn+1={yield vif Sn reaches yieldreturn vif Sn reaches return

总结[编辑 | 编辑源代码]

JavaScript生成器提供了:

  • 按需生成值的惰性计算能力
  • 更清晰的异步代码控制流
  • 简化迭代器实现的语法糖
  • 与其他语言特性(如async/await)的深度集成

虽然现代JavaScript中async/await更常用于处理异步操作,但生成器仍然是处理复杂控制流、数据流和状态管理的强大工具。