Generator 函数
ES6 引入的生成器函数,可以暂停和恢复函数执行,返回一个迭代器对象(Iterator),通常与 Promise 结合使用
案例
基础语法
js
// 1. 定义生成器函数
function* gen() {
yield 1;
yield 2;
yield 3;
}
// 2. 调用函数不会立即运行,只返回迭代器
const g = gen();
// 3. 真正执行靠 .next()
console.log(g.next()); // { value: 1, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.next()); // { value: 3, done: false }
console.log(g.next()); // { value: undefined, done: true }给 yield 传参
js
function* gen() {
const a = yield 'first';
const b = yield a;
yield a + b;
}
const g = gen();
g.next(); // {value: 'first'}
g.next(10); // a = 10
g.next(20); // b = 20
g.next(); // value: 30遍历 Generator 的方法
js
function* gen() {
yield 1;
yield 2;
yield 3;
}
// for of 遍历
for (const v of gen()) {
console.log(v); // 1 2 3
}
// 展开运算符 ...
const arr = [...gen()]; // [1,2,3]
// Array.from
const arrFrom = Array.from(gen()); // [1,2,3]
// 解构赋值
const [a, b, c] = gen();yield* 语法(委托生成器)
在一个 Generator 里执行另一个 Generator
js
function* gen1() {
yield 1;
yield 2;
}
function* gen2() {
yield* gen1();
yield 3;
}
[...gen2()]; // [1,2,3]终止 yield
js
// return 提前结束
function* gen() {
yield 1;
yield 2;
yield 3;
}
const g = gen();
g.next(); // 1
g.return(99);
g.next(); // done: true
// throw 捕获异常
function* gen() {
try {
yield 1;
} catch (err) {
console.log('捕获', err);
}
}
const g = gen();
g.next();
g.throw('错误');异步流程控制
js
function fetchUser() {
return new Promise(resolve => {
setTimeout(() => resolve({ id: 1 }), 1000);
});
}
function* gen() {
const user = yield fetchUser();
console.log(user);
}
// 执行
const g = gen();
g.next().value.then(data => {
g.next(data);
});自动执行器
思想:递归反复调用 next 函数,直到res.done === true 结束递归
shell
# 参数为生成器函数,
function run(genFunc) {
return new Promise((resolve, reject) => {
const it = genFunc(); # 创建迭代器(还没开始遍历)
# 递归遍历函数
function next(arg) {
try {
const res = it.next(arg); # 核心:每执行一次,就往下走一个 yield
# 遍历结束
if (res.done) {
return resolve(res.value);
}
# 还没结束
Promise.resolve(res.value)
.then(next) # 递归:异步完成后,继续递归遍历下一个 next
.catch(reject);
} catch (err) {
reject(err);
}
}
next(); # 启动第一次遍历
});
}进阶练习
shell
# 1. Generator 是什么?
可以暂停和恢复的函数,用 function* 和 yield,返回迭代器,用于异步流程控制。
# 2. next () 做什么?
执行到下一个 yield,返回 { value, done }。
# 3. yield* 和 yield 区别?
yield 返回值;yield* 委托另一个生成器。
# 4. Generator 怎么遍历?
for...of、... 展开、Array.from。
# 5. async/await 和 Generator 关系?
async/await 是基于 Generator 和 Promise 实现的语法糖,内置自动执行器。
# 6. Generator 优点?
逻辑同步化、可暂停、可控性强。
# 7. Generator 与 async/await 的关系
async/await 就是 Generator + Promise 的语法糖
async function ↔ function*
await ↔ yield
自动执行 ↔ 内置 co 逻辑
所以可以理解为:
async function fn() {
const data = await fetch();
}
本质就是:
function* fn() {
const data = yield fetch();
}
加一个自动执行器。