📚 什么是 Generator?
Generator(生成器)是 ES6 引入的一种特殊函数,它可以暂停执行和恢复执行,是实现异步编程和迭代器的强大工具。
🔑 核心特点
- 可暂停:使用
yield 关键字暂停函数执行
- 可恢复:通过
next() 方法恢复执行
- 惰性求值:只在需要时才计算下一个值
- 双向通信:可以在暂停和恢复时传递数据
🎯 基础语法
定义 Generator 函数
1 2 3 4 5 6 7 8 9
| function* generatorFunction() { yield "first"; yield "second"; return "done"; }
const iterator = generatorFunction();
|
next() 方法
1 2 3 4
| iterator.next(); iterator.next(); iterator.next(); iterator.next();
|
💡 执行流程详解
示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function* read() { let a = yield "a"; console.log("a =", a);
let b = yield "b"; console.log("b =", b);
let c = yield "c"; console.log("c =", c);
return "end"; }
const iterator = read();
|
执行步骤分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| console.log(iterator.next());
console.log(iterator.next("x"));
console.log(iterator.next("y"));
console.log(iterator.next("z"));
console.log(iterator.next());
|
完整输出
1 2 3 4 5 6 7 8
| { value: 'a', done: false } a = x { value: 'b', done: false } b = y { value: 'c', done: false } c = z { value: 'end', done: true } { value: undefined, done: true }
|
🔍 关键要点
1. yield 的双重作用
1 2 3 4 5 6 7 8 9
| function* demo() { const result = yield "output"; console.log("received:", result); }
const it = demo(); it.next(); it.next("input");
|
2. 第一次 next() 的参数会被忽略
1 2 3 4 5 6 7 8
| function* demo() { const x = yield 1; console.log(x); }
const it = demo(); it.next("ignored"); it.next("received");
|
原因:第一次调用 next() 时,还没有任何 yield 表达式等待接收值。
🎨 实际应用场景
1. 实现无限序列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function* fibonacci() { let [prev, curr] = [0, 1];
while (true) { yield curr; [prev, curr] = [curr, prev + curr]; } }
const fib = fibonacci(); console.log(fib.next().value); console.log(fib.next().value); console.log(fib.next().value); console.log(fib.next().value); console.log(fib.next().value);
|
2. 遍历数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function* traverseTree(node) { yield node.value;
if (node.children) { for (const child of node.children) { yield* traverseTree(child); } } }
const tree = { value: 1, children: [ { value: 2, children: [{ value: 4 }, { value: 5 }] }, { value: 3 }, ], };
for (const value of traverseTree(tree)) { console.log(value); }
|
3. 控制异步流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| function* fetchData() { console.log("开始获取数据...");
const user = yield fetch("/api/user"); console.log("用户信息:", user);
const posts = yield fetch(`/api/posts/${user.id}`); console.log("用户文章:", posts);
return posts; }
function run(generator) { const iterator = generator();
function handle(result) { if (result.done) return result.value;
result.value .then((data) => data.json()) .then((data) => handle(iterator.next(data))) .catch((err) => iterator.throw(err)); }
handle(iterator.next()); }
run(fetchData);
|
4. 实现迭代器协议
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const range = { from: 1, to: 5,
*[Symbol.iterator]() { for (let value = this.from; value <= this.to; value++) { yield value; } }, };
for (const num of range) { console.log(num); }
console.log([...range]);
|
🆚 Generator vs Async/Await
| 特性 |
Generator |
Async/Await |
| 语法 |
function* + yield |
async + await |
| 返回值 |
Iterator 对象 |
Promise 对象 |
| 执行控制 |
手动调用 next() |
自动执行 |
| 适用场景 |
惰性求值、自定义迭代 |
异步操作 |
| 易用性 |
⭐⭐⭐ |
⭐⭐⭐⭐⭐ |
注意:Async/Await 本质上是基于 Generator 和 Promise 的语法糖。
📊 常用方法
1. next(value)
继续执行并可选地传入一个值给上一个 yield 表达式。
1 2 3 4 5 6 7 8
| function* gen() { const x = yield; console.log(x); }
const g = gen(); g.next(); g.next("hello");
|
2. return(value)
提前终止生成器并返回给定的值。
1 2 3 4 5 6 7 8 9 10
| function* gen() { yield 1; yield 2; yield 3; }
const g = gen(); console.log(g.next()); console.log(g.return("end")); console.log(g.next());
|
3. throw(error)
向生成器抛出一个错误。
1 2 3 4 5 6 7 8 9 10 11
| function* gen() { try { yield 1; } catch (e) { console.log("捕获错误:", e); } }
const g = gen(); g.next(); g.throw(new Error("出错了"));
|
💡 最佳实践
✅ 推荐
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function* generateIds() { let id = 0; while (true) { yield ++id; } }
function* safeGenerator(max) { let count = 0; while (count < max) { yield count++; } }
function* withResource() { const resource = acquireResource(); try { yield resource; } finally { releaseResource(resource); } }
|
❌ 避免
🎯 总结
- Generator 是什么:可暂停和恢复执行的特殊函数
- 核心概念:
yield 暂停,next() 恢复,双向数据传递
- 主要用途:惰性求值、自定义迭代器、流程控制
- 现代替代:对于异步操作,Async/Await 更加简洁和易用
- 学习价值:理解 Generator 有助于深入理解 JavaScript 的异步编程机制 ✨
📚 相关资源