done是测试框架提供的异步回调标记机制,用于通知测试运行器异步操作完成;需在test回调中接收并显式调用,错误时传err,不可与async/await混用。

在 JavaScript 中,done 回调函数常见于测试框架(如 Jest、Mocha、Jasmine)中,用于显式告诉测试运行器:这个异步操作已经完成,可以结束当前测试用例了。它不是 JS 原生语法,而是测试工具提供的机制,专门用来处理“传统回调风格”的异步代码(比如 fs.readFile, setTimeout, 或自定义的 (err, result) => {} 形式)。
下面以 Jest 为例说明怎么用 done 正确测试传统回调函数:
为什么需要 done?
如果测试里有回调(比如 `someAsyncFn((err, data) => { ... })`),而你没告诉 Jest “等我回调执行完再结束”,Jest 就会立即认为测试通过(或超时失败),根本不会等待回调执行。`done()` 就是手动标记“我这异步活干完了”。
基本写法:把 done 传进 test 回调
在 `test` 或 `it` 的回调函数中,**接收一个 `done` 参数**,并在你的回调逻辑最后调用它:
test('should read file successfully', (done) => {
fs.readFile('test.txt', 'utf8', (err, data) => {
if (err) {
done(err); // 传错 error,测试直接失败
return;
}
expect(data).toBe('hello');
done(); // ✅ 告诉 Jest:任务完成
});
});✅ 关键点:
-
必须显式调用
done(),否则测试会超时(Jest 默认 5s 超时) -
出错时调用
done(err),Jest 会把它当测试失败并显示错误堆栈 -
不能同时用
done()和return Promise/async/await,二者互斥
常见错误和注意事项
以下写法容易出问题,需避免:
- 忘记调用 done() → 测试挂起、超时失败
- 在条件分支里漏掉 done()(比如只在 `if` 里调了,`else` 没调)→ 随机超时
- 多次调用 done() → Jest 报警告,可能掩盖真实错误
- 混用 async/await 和 done → Jest 无法协调,行为不可预测
- 在回调外提前调 done() → 测试结束太早,断言还没执行
替代方案:用 Promise 包装回调(更推荐)
如果你能控制被测代码,或方便封装,把回调转成 Promise,就能用 `async/await`,更简洁安全:
// 工具函数:promisify 回调函数(Node.js 有内置 util.promisify)
const readFileAsync = (file, encoding) =>
new Promise((resolve, reject) =>
fs.readFile(file, encoding, (err, data) =>
err ? reject(err) : resolve(data)
)
);
// 测试写法(不用 done)
test('should read file with async/await', async () => {
const data = await readFileAsync('test.txt', 'utf8');
expect(data).toBe('hello');
});✅ 这样无需手动管理 done,错误自动抛出,逻辑更清晰。


















