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()
时,生成器从上次暂停的位置继续执行,直到遇到下一个yield
或return
。
状态图[编辑 | 编辑源代码]
实际应用[编辑 | 编辑源代码]
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 }
数学表达[编辑 | 编辑源代码]
生成器的暂停/恢复行为可以用状态机表示。设生成器的状态为,则:
总结[编辑 | 编辑源代码]
JavaScript生成器提供了:
- 按需生成值的惰性计算能力
- 更清晰的异步代码控制流
- 简化迭代器实现的语法糖
- 与其他语言特性(如async/await)的深度集成
虽然现代JavaScript中async/await
更常用于处理异步操作,但生成器仍然是处理复杂控制流、数据流和状态管理的强大工具。