async/await的核心思路是用Generator函数模拟异步暂停/恢复,配合自动执行器(如co)驱动:yield交出Promise,执行器通过then递归next传值,实现流程线性化。

手写 async/await 的核心思路,是用 Generator 函数模拟异步暂停/恢复语义,再配合一个自动执行器(类似 co 库)来驱动它一步步执行,遇到 yield 后的 Promise 就自动 then 接续,把异步流程“线性化”。
Generator 是 async/await 的语法骨架
Generator 函数通过 function* 声明,用 yield 暂停执行、返回中间值;调用其 next() 方法可恢复,并传入值继续。这和 await 暂停等待 Promise 完成、解包结果的行为高度相似:
async function foo() { const a = await fetch('/api'); return a.json(); }- 等价于 Generator 形式:
function* foo() { const a = yield fetch('/api'); return yield a.json(); }
注意:Generator 本身不处理 Promise,yield fetch('/api') 只是把 Promise 对象交出去,真正“等它完成并把结果送回来”,得靠外部执行器。
自动执行器(co 风格)负责调度与递归推进
执行器接收 Generator 函数,调用它得到迭代器,然后反复调用 next(),对每次返回的 { value, done } 做判断:
立即学习“Java免费学习笔记(深入)”;
- 如果
done === true,说明执行完毕,用resolve(value)结束 Promise - 如果
value是 Promise,就.then(res => next(res))把结果送回下一轮next() - 如果
value不是 Promise(如普通值、null、对象),直接next(value)继续 - 出错时捕获并
reject(err)
关键点在于:执行器自己返回一个 Promise,并在内部用递归(或循环 + Promise 链)实现自动“接棒”。
手写简易 co 执行器示例
以下是一个最小可用版本(支持 Promise、普通值、错误传播):
function co(genFn) {
return new Promise((resolve, reject) => {
const gen = genFn();
<pre class="brush:php;toolbar:false;">function step(nextFn, err, value) {
try {
const { value: v, done } = nextFn(err, value);
if (done) {
resolve(v);
} else if (v instanceof Promise) {
v.then(res => step(gen.next, null, res), err => step(gen.throw, err));
} else {
step(gen.next, null, v);
}
} catch (e) {
reject(e);
}
}
step(gen.next);}); }
使用方式:
function* fetchData() {
const res = yield fetch('/api');
const json = yield res.json();
return json.data;
}
<p>co(fetchData).then(console.log).catch(console.error);async/await 与手写 co 的关键差异
浏览器/Node.js 中原生 async/await 是语言级特性,由引擎直接编译为状态机(而非依赖 Generator),性能更好、调试更友好、支持 await 任意 thenable、能正确处理 return/throw 语义等。而手写 co:
- 依赖
yield,必须用 Generator 函数包装 - 不能直接
await,只能yieldPromise - 错误需靠
gen.throw()注入,不如原生try/catch直观 - 不支持
yield数组/对象并发(需额外扩展,如co.all)
所以手写 co 主要用于理解原理、兼容旧环境或定制执行逻辑,生产环境应优先用原生 async/await。


















