生成器函数通过yield暂停恢复执行,为异步流程管理提供基础,虽被async/await取代,但在协程状态机、redux-saga等高级场景仍有价值。
JavaScript 中的生成器函数(Generator Function)本身并不直接处理异步操作,但它通过 yield
暂停和恢复执行的特性,为手动或配合工具库(如 co、redux-saga)管理异步流程提供了强大基础。现代开发中虽被 async/await 大量取代,但理解它有助于深入掌握控制流机制和某些高级场景(如协程式状态机、中间件流)。
生成器函数用 function* 声明,返回一个迭代器对象;调用 next() 方法可逐步执行到下一个 yield 表达式,并获取其值。
示例:
function* countDown(n) {
while (n > 0) {
yield n;
n--;
}
return 'done';
}
const iterator = countDown(3);
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 'done', done: true }
生成器不自动等待 Promise,但你可以手动捕获 yield 出的 Promise,在 then 中继续调用 next,从而实现“暂停等待异步结果”的效果。
核心思路是写一个“执行器”(runner),递归处理每个 yield 返回的 Promise:
gen.next(value) 获取下一步的 {value, done}
value 是 Promise,用 .then(res => runner(res)) 继续执行done 为 true,结束流程简化版执行器示例:
function run(genFn) {
const gen = genFn();
function next(data) {
const result = gen.next(data);
if (result.done) return result.value;
result.value.then(next);
}
next();
}
// 使用
function* fetchUser() {
const res = yield fetch('/api/user');
const user = yield res.json();
console.log(user.name);
}
run(fetchUser);
生成器+执行器的方式本质是手写协程调度器,而 async/await 是语言级支持,更简洁可靠:
async/await 自动处理 Promise 链、错误传播(try/catch 直接捕获异步错误)async/await,无需 polyfill 或工具库不过在特定框架中仍有价值:比如 redux-saga 利用生成器实现可测试、可撤销、可回溯的副作用管理,把异步逻辑从组件中抽离为声明式“saga”。
日常业务开发优先使用 async/await。仅在以下情况可考虑生成器:
co 或 redux-saga 代码它不是过时的技术,而是退居幕后成为底层能力——就像你不用手写红黑树,但理解它能帮你更好用 Map 和 Set。