generator 本身不直接处理异步,但可通过 co 库或手动调用 next()/throw() 模拟异步流程;jest v26+ 已移除原生支持,推荐优先使用 async/await。

Generator 迭代器本身不直接处理异步,但配合 co、jest 的旧式支持(v26 前)或手动调用 next() / throw() 可模拟异步流程控制。现代测试中更推荐用 async/await,但若需兼容老代码或理解底层机制,仍可编写基于 generator 的异步测试。
用 co + generator 编写可等待的测试逻辑
co 是一个将 generator 自动转为 Promise 的小工具,能让你在 generator 内用 yield 等待异步操作。它适合 Jest v26 之前(Jest 曾原生支持 generator 测试函数)。
安装:npm install co --save-dev
示例:测试一个返回 Promise 的函数 fetchUser(id)
const co = require('co');
<p>test('generator test with co', () => {
return co(function* () {
const user = yield fetchUser(123);
expect(user.name).toBe('Alice');
expect(user.id).toBe(123);
});
});
</p>
注意:Jest 会自动等待返回的 Promise,所以整个 co(...) 调用必须被 return。
手动驱动 generator 实现细粒度控制
适合调试 generator 行为,或验证迭代器状态(如是否抛出错误、中间值是否符合预期)。
- 创建 generator 函数(带
function*) - 调用它得到迭代器对象
- 用
next()触发每一步,传入上一步 resolve 的值 - 用
throw()模拟 Promise reject
示例:
function* userFlow() {
const res = yield fetchUser(123);
return res.name.toUpperCase();
}
<p>test('manually drive generator', () => {
const it = userFlow();</p><p>// 第一次 next,得到 { value: Promise, done: false }
let step1 = it.next();
expect(step1.done).toBe(false);</p><p>// 模拟 fetchUser 成功
step1.value.then((user) => {
// 把 user 传给下一次 next
let step2 = it.next(user);
expect(step2.value).toBe('ALICE');
expect(step2.done).toBe(true);
});
});
</p>
⚠️ 此方式需手动处理 Promise 链,容易出错,仅用于教学或特殊断言场景。
Jest 中 generator 测试的注意事项
- Jest v26+ 已移除对
function*测试函数的原生支持,直接写test('xxx', function* () { ... })会报错或静默跳过 - 若使用
co,确保返回 Promise,否则 Jest 认为同步测试已结束 - 避免混用
yield和await—— generator 和 async 函数是不同机制,不可嵌套混用 - 错误处理建议用
try/catch包裹yield,或在co外层.catch()
更现代的替代方案(推荐)
除非维护遗留 generator 逻辑,否则应优先使用:
-
async/await:语义清晰、调试友好、Jest 原生支持 -
jest.mock()+mockResolvedValue():精准控制异步依赖返回 - 第三方库如
wait-for-expect:应对真实延迟或副作用
例如等价写法:
test('modern async test', async () => {
const user = await fetchUser(123);
expect(user.name).toBe('Alice');
});
简洁、可靠、易读,且与当前 JS 生态完全对齐。











