以下回答主要由 Deepseek AI 生成,经博主本人审核和增删整理,如有错漏请评论区反馈。
JavaScript Generator 函数全面总结
Generator 基础概念
| 项目 |
描述 |
示例 |
| 定义 |
能暂停和恢复执行的函数,使用 function* 声明 |
function* gen() { yield 1; } |
| yield 关键字 |
暂停函数执行并返回一个值 |
yield expression; |
| next() 方法 |
恢复函数执行,返回 {value, done} 对象 |
gen.next() |
| 返回值 |
返回一个 Generator 对象(可迭代对象) |
符合迭代协议和迭代器协议 |
Generator 函数声明方式
| 方式 |
语法 |
说明 |
| 函数声明 |
function* generator() { yield 1; } |
标准的声明方式 |
| 函数表达式 |
const generator = function*() { yield 1; } |
赋值给变量 |
| 对象方法 |
const obj = { *generator() { yield 1; } } |
方法简写形式 |
| 类方法 |
class A { *generator() { yield 1; } } |
类中的生成器方法 |
Generator 对象方法
| 方法 |
参数 |
返回值 |
作用 |
| next() |
value (可选) |
{ value: any, done: boolean } |
恢复执行,直到下一个 yield |
| return() |
value (可选) |
{ value, done: true } |
立即终止生成器 |
| throw() |
error |
{ value, done } |
向生成器抛出错误 |
yield 表达式行为
| 场景 |
行为 |
示例 |
| 基本 yield |
暂停执行,返回右侧表达式的值 |
yield 1 → {value: 1, done: false} |
| yield 接收值 |
通过 next() 参数向生成器传递值 |
const input = yield; |
| yield* |
委托给另一个生成器或可迭代对象 |
yield* [1, 2, 3] |
| return 语句 |
终止生成器,done 变为 true |
return 'end' → {value: 'end', done: true} |
执行流程控制
| 步骤 |
代码示例 |
执行结果 |
| 创建生成器 |
const gen = generator(); |
生成器对象,未开始执行 |
| 第一次 next() |
gen.next() |
执行到第一个 yield,返回 yield 的值 |
| 传递值 |
gen.next('hello') |
恢复执行,'hello' 赋给上一个 yield 表达式 |
| 最终完成 |
gen.next() |
返回 {value: undefined, done: true} |
实际应用场景
| 场景 |
代码示例 |
优势 |
| 惰性求值 |
function* fibonacci() { let [a, b] = [0, 1]; while(true) { yield a; [a, b] = [b, a + b]; } } |
按需生成,无限序列 |
| 状态机 |
function* stateMachine() { while(true) { yield 'state1'; yield 'state2'; } } |
清晰的状态管理 |
| 异步控制流 |
function* asyncFlow() { const user = yield fetchUser(); const posts = yield fetchPosts(user.id); } |
类似同步的异步编程 |
| 数据流处理 |
function* pipeline(data) { data = yield* transform1(data); data = yield* transform2(data); return data; } |
可组合的数据处理 |
使用生成器的情况
| 场景 |
理由 |
示例 |
| 惰性求值 |
按需生成值,节省内存 |
无限序列、大数据集 |
| 状态管理 |
维护复杂状态机 |
游戏状态、工作流 |
| 数据流处理 |
构建处理管道 |
数据转换流水线 |
| 自定义迭代 |
实现复杂的迭代逻辑 |
树遍历、特殊数据结构 |
生成器的独特应用场景
1. 惰性计算和无限序列
javascript
复制代码
// 生成器:无限序列 - async/await 无法替代
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. 状态机和协程
javascript
复制代码
// 生成器:状态机 - async/await 无法替代
function* trafficLight() {
while (true) {
yield 'red';
yield 'green';
yield 'yellow';
}
}
const light = trafficLight();
console.log(light.next().value); // 'red'
console.log(next().value); // 'green'
console.log(light.next().value); // 'yellow'
console.log(light.next().value); // 'red' (循环)
3. 数据流处理管道
javascript
复制代码
// 生成器:数据处理管道
function* numbers() {
let i = 0;
while (i < 5) {
yield i++;
}
}
function* double(iterable) {
for (const item of iterable) {
yield item * 2;
}
}
function* filterEven(iterable) {
for (const item of iterable) {
if (item % 2 === 0) {
yield item;
}
}
}
// 组合生成器
const pipeline = filterEven(double(numbers()));
console.log([...pipeline]); // [0, 4, 8]
Generator 与迭代协议
| 特性 |
描述 |
示例 |
| 可迭代对象 |
Generator 对象实现了 [Symbol.iterator] |
for (const value of gen()) |
| 迭代器协议 |
有 next() 方法,返回 {value, done} |
符合迭代器标准 |
| yield* 委托 |
迭代另一个可迭代对象 |
yield* [1, 2, 3] |
| 提前终止 |
return() 方法实现可选的迭代器方法 |
gen.return('stop') |
错误处理
| 方式 |
语法 |
行为 |
| 内部 try/catch |
try { yield risky(); } catch(e) { } |
捕获生成器内部的错误 |
| throw() 方法 |
gen.throw(new Error()) |
从外部向生成器抛出错误 |
| 生成器内部抛出 |
throw new Error() |
错误会传播到外部 |
Generator 与异步编程
| 模式 |
代码示例 |
说明 |
| 传统回调 |
function* asyncGen() { const data = yield fs.readFile('file', cb); } |
需要外部运行器 |
| Promise 配合 |
function* asyncGen() { const data = yield fetch(url); return data.json(); } |
需要自动执行器 |
| async/await 关系 |
async/await 是 Generator + Promise 的语法糖 |
更简洁的异步解决方案 |
常用工具模式
基础运行器
javascript
复制代码
function runGenerator(genFunc) {
const gen = genFunc();
function step(nextValue) {
const result = gen.next(nextValue);
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value).then(step, err => gen.throw(err));
}
return step();
}
状态机示例
javascript
复制代码
function* trafficLight() {
while (true) {
yield 'red';
yield 'green';
yield 'yellow';
}
}
const light = trafficLight();
console.log(light.next().value); // 'red'
console.log(light.next().value); // 'green'
注意事项和限制
| 限制 |
描述 |
解决方案 |
| 不能箭头函数 |
箭头函数不能用作生成器 |
使用 function* 声明 |
| 一次性的 |
生成器对象遍历一次后耗尽 |
重新调用生成器函数创建新对象 |
| 性能开销 |
暂停/恢复机制有性能成本 |
在性能关键代码中谨慎使用 |
| 调试复杂性 |
执行流程不如普通函数直观 |
使用调试工具和清晰的命名 |
浏览器兼容性
| 环境 |
Generator 支持 |
备注 |
| 现代浏览器 |
✅ Chrome 39+, Firefox 26+, Safari 10+ |
全面支持 |
| Node.js |
✅ Node.js 4.0+ |
需要 --harmony flag 或 6.0+ 完全支持 |
| Babel 转译 |
✅ 通过 regenerator-runtime |
兼容旧环境 |
| TypeScript |
✅ 全面支持 |
编译为 ES5/ES6 |
Generator 函数为 JavaScript 带来了协程-like 的能力,是实现惰性计算、状态机和复杂控制流的强大工具,同时也是 async/await 的底层基础。
JavaScript 生成器 vs Async/Await
生成器没有被 async/await 取代,它们有各自不同的应用场景。
Async/await 是生成器在异步编程方面的语法糖,但生成器在其他领域仍有不可替代的价值。
| 特性 |
生成器 (Generator) |
Async/Await |
关系 |
| 主要用途 |
惰性计算、状态机、数据流 |
异步操作控制流 |
不同领域 |
| 语法 |
function* + yield |
async + await |
语法相似但用途不同 |
| 返回值 |
Generator 对象 |
Promise |
完全不同 |
| 执行控制 |
可暂停、可恢复 |
自动暂停、自动继续 |
生成器更底层 |
生成器没有被取代,而是:
-
在异步编程领域:Async/Await 提供了更简洁的语法,可以看作是生成器的"升级版"
-
在其他领域:生成器在惰性计算、状态机、数据流处理等方面仍有不可替代的价值
-
互补关系:它们解决不同的问题,在现代 JavaScript 中共存
选择建议:
-
处理异步操作 → 使用 Async/Await
-
处理复杂状态、惰性计算、数据流 → 使用生成器
-
需要精细控制执行流程 → 使用生成器
关联阅读推荐
JavaScript 生成器与迭代器对比(附:Array Iterator 对象详解)
JavaScript Promise 全面总结
JavaScript async/await 全面总结
JavaScript 懒加载全面总结