JavaScript Generator 函数详解:从基础到高级应用
Generator 是 JavaScript 中一种特殊的函数,它可以通过 yield
关键字暂停和恢复执行,为异步编程、惰性求值和迭代器模式提供了强大的支持。
1. Generator 基础
1.1 基本语法
Generator 函数通过 function*
声明,内部使用 yield
暂停执行,并通过 .next()
恢复执行。
function* simpleGenerator() {
yield 'First value';
yield 'Second value';
return 'Done';
}
const gen = simpleGenerator();
console.log(gen.next()); // { value: 'First value', done: false }
console.log(gen.next()); // { value: 'Second value', done: false }
console.log(gen.next()); // { value: 'Done', done: true }
1.2 yield
和 next()
的交互
yield
:暂停函数执行,并返回右侧的值。.next()
:恢复执行,可以传入参数作为yield
的返回值。
function* genWithInput() {
const a = yield 'First yield';
const b = yield a + ' Second yield';
return b;
}
const gen = genWithInput();
console.log(gen.next()); // { value: 'First yield', done: false }
console.log(gen.next('Hello')); // { value: 'Hello Second yield', done: false }
console.log(gen.next('End')); // { value: 'End', done: true }
2. Generator 高级用法
2.1 生成无限序列
Generator 可以惰性计算,适合生成无限数据流。
function* infiniteNumbers() {
let n = 0;
while (true) {
yield n++;
}
}
const numbers = infiniteNumbers();
console.log(numbers.next().value); // 0
console.log(numbers.next().value); // 1
// ...可以无限调用
2.2 实现自定义迭代器
Generator 函数天然支持 Symbol.iterator
,可以用于自定义迭代逻辑。
const myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
for (const num of myIterable) {
console.log(num); // 1, 2, 3
}
2.3 异步 Generator(for-await-of
)
结合 async
和 yield
,可以处理异步数据流。
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}
(async () => {
for await (const num of asyncGenerator()) {
console.log(num); // 1, 2, 3
}
})();
3. Generator 与协程(Coroutine)
Generator 可以模拟协程(Coroutine),实现更复杂的控制流。
3.1 协程调度示例
function* taskA() {
console.log('Task A - Step 1');
yield;
console.log('Task A - Step 2');
}
function* taskB() {
console.log('Task B - Step 1');
yield;
console.log('Task B - Step 2');
}
const a = taskA();
const b = taskB();
a.next(); // "Task A - Step 1"
b.next(); // "Task B - Step 1"
a.next(); // "Task A - Step 2"
b.next(); // "Task B - Step 2"
3.2 结合 co
库实现自动执行
// 模拟 co 库(自动执行 Generator)
function co(generator) {
const gen = generator();
function handle(result) {
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value)
.then((res) => handle(gen.next(res)))
.catch((err) => handle(gen.throw(err)));
}
return handle(gen.next());
}
co(function* () {
const data1 = yield Promise.resolve(1);
const data2 = yield Promise.resolve(2);
console.log(data1 + data2); // 3
});
4. Generator 实战应用
4.1 实现 Redux-Saga 风格的异步流
function* userSaga() {
try {
const user = yield call(fetchUser);
yield put({ type: 'USER_LOADED', payload: user });
} catch (error) {
yield put({ type: 'USER_ERROR', error });
}
}
4.2 实现分页数据流
async function* paginatedData(url) {
let page = 1;
while (true) {
const response = await fetch(`${url}?page=${page}`);
const data = await response.json();
if (data.length === 0) break;
yield data;
page++;
}
}
(async () => {
for await (const items of paginatedData('/api/data')) {
console.log(items);
}
})();
5. Generator vs Async/Await
特性 | Generator | Async/Await |
---|---|---|
语法 | function* + yield | async + await |
返回值 | 迭代器对象({value, done} ) | Promise |
适用场景 | 复杂控制流、惰性计算 | 简单异步代码 |
自动执行 | 需要手动 .next() 或 co | 自动执行 |
错误处理 | try/catch + .throw() | try/catch |
总结
- Generator 的核心:
function*
+yield
,可暂停和恢复执行。 - 主要用途:
- 惰性计算(无限序列)。
- 自定义迭代器(
Symbol.iterator
)。 - 异步控制流(结合
for-await-of
或co
)。
- 高级应用:协程、Redux-Saga、分页数据流。