Generator 本身不能直接解决回调地狱,需配合 yield 和执行器将嵌套异步转为线性流程;它通过暂停/恢复机制显式交出“等待点”,由执行器调度异步任务并传回结果,实现扁平化控制流。

Generator 本身不能直接“解决”回调地狱,但它配合 yield 和手动/自动的执行器(如 co 或自研 runner),可以把嵌套的异步回调结构,转换成看起来同步、实际异步的线性流程。关键不在于 Generator 自己执行异步,而在于它能暂停和恢复,并把异步操作的“等待点”显式交由执行器调度。
用 yield 暂停,把回调塞进 next() 的 value 中
Generator 函数返回一个迭代器,每次调用 next() 会运行到下一个 yield,并把 yield 后的值(比如一个 Promise、Node 回调风格函数、甚至一个带 then 方法的对象)作为 { value, done } 的 value 字段。执行器拿到这个 value,判断它是异步任务后,等它完成再调用下一次 next(result) 把结果传回去。
- 你写的 Generator 里不用写
callback,也不用.then()嵌套 - 每个
yield后面放一个“可被执行器识别的异步描述”,比如yield readFile('a.txt') - 执行器负责:取
value→ 判断是否可 await(或是否带then)→ 等它 resolve → 调next(resolvedValue)
手写一个最小可用执行器(co 风格)
不需要第三方库,十几行就能跑通基本流程:
function run(genFn) {
const gen = genFn();
function next(data) {
const { value, done } = gen.next(data);
if (done) return value;
// 假设 value 是 Promise
return value.then(next).catch(err => gen.throw(err));
}
return next();
}然后这样写业务逻辑:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
function* main() {
const a = yield fetch('/api/a').then(r => r.json());
const b = yield fetch(`/api/b?id=${a.id}`).then(r => r.json());
const c = yield fetch(`/api/c?x=${b.x}`).then(r => r.json());
return c;
}
<p>run(main); // 返回一个 Promise,最终 resolve(c)三层嵌套的 .then() 回调,变成了三行 yield,结构完全扁平。
支持 Node.js 回调风格(err, data)的适配
很多老 API 是 fs.readFile(path, cb) 这种形式。你可以封装一层:
- 写个
promisify(fn)工具函数,把(...args, cb)转成返回 Promise 的函数 - 或者让执行器识别形如
{ then: fn, catch: fn }或带then方法的对象即可 - 更简单:在 Generator 里直接
yield new Promise((res, rej) => fs.readFile(..., (err, data) => err ? rej(err) : res(data)))
注意:Generator 不是 async/await,别混淆角色
ES2017 的 async/await 实际上就是 Generator + 自动执行器的语法糖升级版。但理解 Generator 流程有助于明白底层发生了什么:
-
async function编译后本质是function*加自动 runner -
await对应yield,只是语言层面做了封装,无需手动写执行器 - Generator 本身是中立的:yield 什么,next 就传什么;它不关心 value 是 Promise、thunk、还是字符串
所以改造回调地狱的核心思路不是“用 Generator 写异步”,而是“用 yield 标记暂停点,把控制权交给执行器统一调度异步完成逻辑”。

















