generator 无法自动捕获异步拒绝,必须由调用方通过 iterator.throw() 将错误反向注入 yield 暂停点,使内部 try...catch 生效;现代开发应优先使用 async/await。

Generator 本身不直接处理异步拒绝(如 Promise.reject),也不能在 yield 处自动捕获外部 Promise 的 rejection —— 因为 yield 只是暂停执行并交出控制权,它不隐式 await 或 try-catch 异步值。所谓“用外部迭代器反向注入 try-catch”,本质是:**由调用方(即驱动 generator 的代码)负责对 yield 出来的 Promise 做错误处理,并在出错时主动调用 iterator.throw(),把错误“抛回” generator 内部,使其能在 generator 函数体中被 try...catch 捕获。**
关键机制:iterator.throw() 是“反向注入”的唯一入口
Generator 函数返回的迭代器对象提供 .throw(error) 方法。当调用它时,generator 会从上次暂停的 yield 表达式处恢复,并立即将传入的 error 抛出——就像那个 yield 语句本身发生了异常一样。这是让 generator 内部 try...catch 生效的必要条件。
-
不能依赖 Promise 自身的 .catch() 来触发 generator 内部 catch:比如
yield Promise.reject('oops')后,如果外部只是next().value.catch(...),错误不会进入 generator。 -
必须显式调用
iterator.throw(err):这才会让控制流跳回 generator,触发其内部的catch块。 - generator 必须在 yield 点附近有 try/catch:否则 throw 进去仍会向上冒泡到调用方。
标准协作模式:手动驱动 + 错误转发
典型做法是写一个封装函数(如 runGenerator),它:
- 调用
next()获取下一个{ value, done }; - 若
value是 Promise,则用.then()和.catch()分别处理成功/失败; - 成功时递归调用
next(value); - 失败时调用
iterator.throw(err),把错误送回 generator。
示例:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
function runGenerator(genFn) {
const it = genFn();
function handle(result) {
if (result.done) return result.value;
const p = Promise.resolve(result.value);
return p.then(
val => handle(it.next(val)),
err => handle(it.throw(err)) // ← 关键:错误时 throw 回 generator
);
}
return handle(it.next());
}
<p>// 使用:
function* myGen() {
try {
const data = yield fetch('/api');
return data.json();
} catch (e) {
console.error('Fetch failed inside generator:', e);
return null;
}
}</p><p>runGenerator(myGen); // 自动处理 fetch 拒绝并注入 catch</p>注意边界情况与限制
-
throw() 仅对当前暂停点有效:如果 generator 已经
done: true,再调用throw()会报错或静默忽略(取决于环境)。 -
yield 后必须有 try/catch,否则错误会穿透出去:即使你调用了
throw(),若 generator 内没包住,错误仍会抛给调用栈上层。 -
无法“注入”到任意历史 yield 点:
throw()总是作用于最近一次暂停的位置,不能跳转到之前的 yield。 -
同步错误也可用 throw() 注入:比如
it.throw(new Error('sync'))同样触发 generator 内 catch,不限于异步场景。
现代替代方案更推荐 async/await
虽然 generator + iterator.throw() 能实现类似 async/await 的错误传播,但它的手动驱动复杂、可读性差、生态支持弱(如主流库、调试工具都默认适配 async)。除非你在写底层协程调度器或兼容极老环境,否则应优先使用 async function:
-
await天然支持 Promise rejection 捕获; -
try/catch直接包裹 await 表达式; - 错误堆栈清晰,调试友好;
- 无需手写驱动逻辑。
Generator 的这种用法,如今更多见于 redux-saga 等特定中间件中,由框架完成驱动和错误注入,而非业务代码直写。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










