Node.js 如何实现 sleep(等待)?
Node.js 没有内置 sleep 函数,用 Promise 包装 setTimeout 即可:await new Promise(r => setTimeout(r, 3000))。Node 15+ 可用 timers/promises 的 setTimeout。注意千万别用同步忙等阻塞事件循环。
标准写法:Promise 包一层 setTimeout,然后 await 它。
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function example() {
console.log('开始');
await sleep(3000); // 等 3 秒
console.log('结束');
}
example();
这种等待是非阻塞的:等待期间事件循环照常处理其他请求,这是它和"同步 sleep"的本质区别。
更省事:Node 15+ 内置版
const { setTimeout: sleep } = require('timers/promises');
await sleep(3000); // 等 3 秒
await sleep(1000, '返回值'); // 还支持第二个参数作为 resolve 的值
ESM:import { setTimeout as sleep } from 'timers/promises';
循环里逐个处理(常见真实需求)
for (const item of items) {
await process(item);
await sleep(500); // 每个请求间隔 500ms,防止打爆下游 API
}
注意必须 for...of + await;forEach 里 await 不生效(见本系列《forEach 里能用 async/await 吗》)。
警告:别用忙等待
// ❌ 千万别这么写:忙等会把事件循环彻底卡死,整个服务无响应
function badSleep(ms) {
const end = Date.now() + ms;
while (Date.now() < end) {}
}
Node 是单线程事件循环,忙等期间所有请求都得不到处理。需要同步阻塞的场景(几乎没有),正确做法也是把任务挪到 worker_threads。
常见问题(FAQ)
Q:setTimeout 的计时不准怎么办?
setTimeout 保证"至少这么久",不保证精确——事件循环忙时会延后。setInterval 同样不能保证精确时刻;需按实际时间修正漂移,严格实时任务不能依赖普通 JavaScript 定时器。
Q:sleep 能中途取消吗?
timers/promises 的 setTimeout 支持 AbortSignal:await sleep(5000, null, { signal }),外部 controller.abort() 即取消。
Q:测试里怎么 mock 掉 sleep?
注入 sleep 函数作为依赖,测试中替换成立即 resolve 的桩;或用 fake timers(sinon / vitest 自带)。