可以用 Generator + Promise 手动实现简易 async/await 执行器,核心是用 next() 驱动 Generator,遇到 Promise 时通过 then 暂停并等待 resolve 后继续执行,支持错误捕获与 throw,兼容函数和生成器对象。

可以用 Generator + Promise 手动实现一个简易的 async/await 执行器,核心思路是:把 async 函数编译成 Generator 函数,用 next() 驱动执行,遇到 Promise 就用 then 暂停并等待其 resolve 后继续 next。
理解执行器要做什么
async 函数本质上是语法糖,等价于返回 Promise 的 Generator 函数。执行器(runner)的作用就是自动调用 next(),并在 yield 出 Promise 时暂停,等它 settle 后再把结果传回 next(value),直到 Generator 完成。
- 接收一个 Generator 函数(或生成器对象)
- 调用
next()获取第一个{ value, done } - 若
value是 Promise,用then等待;resolve 后递归调用next(result) - 若
done为 true,返回Promise.resolve(value) - 若中间 reject,抛出错误(模拟 await 抛错行为)
基础版 runner 实现
不支持 throw、return、嵌套异步等高级特性,但能跑通基本流程:
function run(genFn) {
const gen = genFn();
<p>function next(data) {
const res = gen.next(data);
if (res.done) return Promise.resolve(res.value);</p><pre class="brush:php;toolbar:false;">return Promise.resolve(res.value).then(
val => next(val),
err => gen.throw(err)
);}
return next(); }
用法示例:
function delay(ms) {
return new Promise(r => setTimeout(r, ms));
}
<p>const myAsync = function* () {
const a = yield delay(100);
const b = yield Promise.resolve(42);
return a + b;
};</p><p>run(myAsync).then(console.log); // 42(a 是 undefined,b 是 42)</p>
支持错误捕获和 throw
原生 async/await 中 try/catch 能捕获 await 抛出的错误,对应到 Generator 就是 gen.throw()。改进 runner 加入错误分支:
function run(genFn) {
const gen = genFn();
<p>function next(data) {
try {
const res = gen.next(data);
if (res.done) return Promise.resolve(res.value);</p><pre class="brush:php;toolbar:false;"> return Promise.resolve(res.value).then(
val => next(val),
err => {
try {
const rejected = gen.throw(err);
return next(rejected.value);
} catch (e) {
return Promise.reject(e);
}
}
);
} catch (e) {
return Promise.reject(e);
}}
return next(); }
这样就能处理 yield Promise.reject(new Error('oops')) 并被外层 try/catch 捕获。
可选:兼容普通函数与生成器对象
让 runner 支持传入函数或直接传入生成器实例:
function run(genOrFn) {
const gen = typeof genOrFn === 'function' ? genOrFn() : genOrFn;
<p>function next(data) {
// ...同上
}</p><p>return next();
}</p>
也方便单元测试时直接传 myGen() 而非 myGen。
不复杂但容易忽略细节:Promise.resolve 包一层是为了统一处理同步值(如 yield 123)和异步值;gen.throw 必须在 try/catch 内调用,否则会中断 runner;实际生产中建议用 co 或现代 runtime,但手写一遍能深入理解 async/await 底层机制。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











