如何实现一个同步的 sleep 函数?
探讨在 JavaScript 中实现同步 sleep 函数的方法及其优缺点。
JavaScript 是单线程非阻塞的,因此通常采用异步方式实现非阻塞等待(推荐方案)。但若需同步阻塞主线程的 sleep,可通过忙等待循环实现。以下是两种方案:
1. 同步阻塞 sleep(不推荐)
循环占用主线程直至超时,导致界面冻结、交互无响应:
function sleep(ms) {
const start = Date.now();
while (Date.now() - start < ms) {} // 忙等待阻塞主线程
}
// 使用示例
console.log("开始等待");
sleep(1000); // 阻塞 1 秒
console.log("等待结束");
严重缺陷:
- 造成浏览器或 Node.js 主线程完全冻结
- 阻塞事件循环和渲染,导致 UI 无响应(按钮/动画卡死)
- 仅限特殊场景(如 Web Worker)
2. 异步 sleep(推荐方案)
通过 Promise
+ setTimeout
实现非阻塞等待,配合 async/await
同步化代码流程:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// 使用示例
async function demo() {
console.log("开始等待");
await sleep(1000); // 暂停 1 秒但不阻塞主线程
console.log("等待结束");
}
demo();
优势:
- 释放主线程供其他任务运行(UI 渲染、事件处理)
- 代码逻辑保持线性可读,无回调嵌套
- 工程扩展性强(支持传参/错误处理):
function sleep(ms, data) { return new Promise(resolve => setTimeout(() => resolve(data), ms)); } async function demo() { const result = await sleep(1000, "同步数据"); console.log(result); // 输出“同步数据” }
[!WARNING] 浏览器环境中始终优先使用异步方案,同步阻塞仅作为特殊需求的备选方案。