JavaScript Generator 函数与异步生成器
Generator 函数是可暂停的函数,yield 暂停执行并产出值,异步生成器结合 Promise 实现复杂的异步流程控制。
Generator 函数基础
JavaScript
// 定义:function* 声明
function* generator() {
yield 1;
yield 2;
yield 3;
}
// 创建迭代器
const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
yield 表达式
JavaScript
function* gen() {
const a = yield 'first'; // yield 返回外部传入的值
console.log('收到:', a); // 收到: 传入值
const b = yield 'second';
console.log('收到:', b);
return 'end';
}
const g = gen();
console.log(g.next()); // { value: 'first', done: false }
console.log(g.next('传入值')); // { value: 'second', done: false },打印"收到: 传入值"
console.log(g.next('另一个值')); // { value: 'end', done: true },打印"收到: 另一个值"
// 第一个 next() 的参数被忽略(Generator 刚启动)
Generator 方法
JavaScript
function* gen() {
try {
yield 1;
yield 2;
yield 3;
} catch (e) {
console.log('捕获错误:', e.message);
}
}
const g = gen();
// next():继续执行
console.log(g.next()); // { value: 1, done: false }
// return():提前终止
console.log(g.return('终止')); // { value: '终止', done: true }
console.log(g.next()); // { value: undefined, done: true }
// throw():在 yield 处抛出错误
const g2 = gen();
g2.next(); // 执行到 yield 1
g2.throw(new Error('迭代器错误')); // 在 yield 1 处抛出错误
yield* 委托
JavaScript
// 委托给另一个 Generator
function* inner() {
yield 'a';
yield 'b';
}
function* outer() {
yield 1;
yield* inner(); // 委托给 inner
yield 2;
}
const gen = outer();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 'a', done: false }
console.log(gen.next()); // { value: 'b', done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: undefined, done: true }
// yield* 可委托任何可迭代对象
function* gen() {
yield* [1, 2, 3]; // 委托数组
yield* 'hello'; // 委托字符串
}
const g = gen();
console.log([...g]); // [1, 2, 3, 'h', 'e', 'l', 'l', 'o']
异步生成器
JavaScript
// async function*:异步生成器
async function* asyncGen() {
yield await fetch('/api/1');
yield await fetch('/api/2');
yield await fetch('/api/3');
}
// 使用 for await...of
(async () => {
for await (const response of asyncGen()) {
const data = await response.json();
console.log(data);
}
})();
// 模拟异步数据流
async function* fetchData(urls) {
for (const url of urls) {
try {
const response = await fetch(url);
yield await response.json();
} catch (e) {
yield { error: e.message };
}
}
}
(async () => {
const urls = ['/api/a', '/api/b', '/api/c'];
for await (const data of fetchData(urls)) {
console.log(data);
}
})();
Generator 实现异步流程
JavaScript
// 传统回调方式
function fetchUser(id, callback) {
setTimeout(() => callback({ id, name: 'User' + id }), 100);
}
// Generator + 自动执行器
function* fetchUsers() {
const user1 = yield fetchUser.bind(null, 1);
const user2 = yield fetchUser.bind(null, 2);
console.log(user1, user2);
}
// 自动执行器(类似 co 库)
function run(generator) {
const gen = generator();
function next(value) {
const result = gen.next(value);
if (result.done) return;
// 如果 yield 返回函数,执行并传入回调
if (typeof result.value === 'function') {
result.value((data) => next(data));
}
}
next();
}
run(fetchUsers);
// Promise 版自动执行器
function promiseRun(generator) {
const gen = generator();
function next(value) {
const result = gen.next(value);
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value).then(next);
}
return next();
}
Generator 实现状态机
JavaScript
// 状态机:有限状态流转
function* stateMachine() {
while (true) {
switch (yield) {
case 'start':
console.log('状态: 开始');
yield 'running';
break;
case 'running':
console.log('状态: 运行中');
yield 'running'; // 保持运行
break;
case 'stop':
console.log('状态: 停止');
return 'end';
}
}
}
const machine = stateMachine();
machine.next(); // 启动 Generator
machine.next('start'); // 输出"状态: 开始",返回 { value: 'running', done: false }
machine.next('running'); // 输出"状态: 运行中"
machine.next('stop'); // 输出"状态: 停止",返回 { value: 'end', done: true }
实际应用场景
JavaScript
// 惰性计算
function* range(start, end) {
while (start < end) {
yield start++;
}
}
for (const n of range(0, 1000000)) {
if (n > 10) break; // 只计算需要的部分
}
// 无限序列
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
// 任务队列
function* taskQueue(tasks) {
for (const task of tasks) {
yield task();
}
}
const tasks = [
() => console.log('任务1'),
() => console.log('任务2'),
() => console.log('任务3')
];
const queue = taskQueue(tasks);
queue.next(); // 执行任务1
queue.next(); // 执行任务2
注意事项
- Generator 函数调用返回迭代器,不立即执行
- 第一个
next()参数被忽略,Generator 刚启动无法接收值return()终止 Generator,执行finally块- 异步生成器必须用
async function*定义
JavaScript
// 第一个 next 参数被忽略
function* gen() {
const x = yield 'first';
console.log(x);
}
const g = gen();
g.next('ignored'); // 参数被忽略
g.next('received'); // 输出 'received'
// finally 在 return 时执行
function* gen() {
try {
yield 1;
} finally {
console.log('清理');
}
}
const g = gen();
g.next();
g.return(); // 执行 finally,输出 '清理'
要点总结
function*定义 Generator,yield暂停并产出值next(value)继续执行,value成为上一个yield的返回值yield*委托给其他 Generator 或可迭代对象return()提前终止,throw()在 yield 处抛出错误async function*异步生成器,yield可接 Promise- 适用于惰性计算、无限序列、状态机、异步流程控制
- 配合自动执行器可实现类似 async/await 的效果
📝 发现内容有误?点击此处直接编辑