JS睡眠函数(JS sleep()函数、JS单线程、Event Loop事件循环)假睡眠

文章目录

💤 JavaScript 中的"睡眠"(JS Sleep)从入门到进阶

在其他语言中(比如 Python 的 time.sleep() 或 C++ 的 std::this_thread::sleep_for()),让程序"暂停"几秒是一件轻而易举的事。

但在 JavaScript 中,当你尝试写下这样的代码时:

js 复制代码
sleep(1000);
console.log("1秒后执行");

你会发现:JS 并没有原生的 sleep() 函数!

为什么会这样?那我们该如何优雅地"让 JavaScript 睡一会儿"?

本文将从最基础的思路讲起,一步步带你深入理解 JS 的异步模型与实现 Sleep 的多种方式。


一、为什么 JavaScript 没有 sleep()

JavaScript 是单线程、事件驱动 的语言。

它运行在一个被称为 Event Loop(事件循环) 的机制中。所有代码(包括定时器回调、异步事件)都要排队执行。

如果存在一个"阻塞"的 sleep(),主线程就会被卡住,页面会假死、无法响应用户操作

所以,JS 并不允许直接阻塞执行。

👉 换句话说:

在 JS 中,"睡眠"只能是非阻塞的。


二、最传统的"伪睡眠":setTimeout()

在早期,我们常用 setTimeout() 来"延迟执行":

js 复制代码
console.log("开始");
setTimeout(() => {
  console.log("1秒后执行");
}, 1000);

运行结果:

复制代码
开始
(1秒后)
1秒后执行

虽然实现了延迟,但语义上并不是"睡眠",而是"计划稍后执行 "。

更重要的是,这种写法不支持顺序等待,比如下面这样:

js 复制代码
setTimeout(() => console.log(1), 1000);
setTimeout(() => console.log(2), 2000);

它不会阻塞第一行等待第二行,而是直接注册两个定时器。


三、用 Promise 封装一个真正的"Sleep"

我们可以借助 Promiseasync/await 实现更像"睡眠"的效果:

js 复制代码
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

使用方法:

js 复制代码
async function demo() {
  console.log("开始");
  await sleep(1000); // 暂停1秒
  console.log("1秒后执行");
}

demo();

输出:

复制代码
开始
(1秒后)
1秒后执行

✅ 这种写法就很接近其他语言的 sleep() 语义。

但注意,这只是让当前 async 函数暂停,并不会阻塞整个线程。


四、理解原理:事件循环与回调队列

await sleep(1000) 时,sleep() 返回了一个 Promise,
await 会让出执行权,JS 引擎继续处理其他任务。

  1. 调用 sleep(1000),注册一个定时器;
  2. 当前 async 函数挂起,JS 主线程继续执行别的任务;
  3. 1000ms 后,定时器触发,Promise 被 resolve()
  4. async 函数恢复执行。

也就是说,这种"暂停"只是协作式的异步等待,不会阻塞整个应用。


五、sleep 的一些高级用法

✅ 1. 循环中使用

js 复制代码
async function countDown(n) {
  for (let i = n; i > 0; i--) {
    console.log(i);
    await sleep(1000);
  }
  console.log("时间到!");
}

countDown(3);

输出:

复制代码
3
2
1
时间到!

✅ 2. 控制异步请求节奏

有时候我们希望在发起多个请求时"限速":

js 复制代码
async function fetchWithDelay(urls) {
  for (const url of urls) {
    const res = await fetch(url);
    console.log(await res.text());
    await sleep(500); // 每次请求间隔0.5秒
  }
}

这种场景在爬虫、防止 API 过载时特别常见。


注意:res.text()返回的是一个Promise,我们需要等待这个Promise解析后才能获取文本内容,没有await,我们得到的将是一个Promise对象,而不是文本内容

✅ 3. 与重试机制结合(重试fetch若干次,中间睡眠一段时间)

js 复制代码
async function fetchWithRetry(url, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const res = await fetch(url);
      return await res.json();
    } catch (e) {
      console.log(`第 ${i + 1} 次失败,等待 2s 重试...`);
      await sleep(2000);
    }
  }
  throw new Error("重试次数耗尽");
}

六、一些需要避免的"假睡眠"方式(完全阻塞主线程)

在 StackOverflow 上常见一些"同步 sleep"写法,例如:

js 复制代码
function busySleep(ms) {
  const start = Date.now();
  while (Date.now() - start < ms) {}
}

⚠️ 千万不要在浏览器中使用!

它会完全阻塞主线程,让页面失去响应,CPU 100%。


七、总结:JS Sleep 的几种方式对比

方法 是否阻塞 可读性 推荐程度
setTimeout 一般 ⭐⭐
Promise + await ⭐⭐⭐⭐
while busy loop ❌ 禁止使用

🧩 结语

JavaScript 虽然没有原生的 sleep() 函数,但通过异步机制,我们依然可以实现优雅、非阻塞的"睡眠"

记住一句话:

JS 的 sleep,不是"让线程睡觉",而是"让任务等待"。

相关推荐
李游Leo3 小时前
Rokid UXR3.0 手势算法与接入实践(v3.0.3)—设备适配、能力边界与示例代码
开发语言
lumi.3 小时前
前端本地存储技术笔记:localStorage 与 sessionStorage 详解
前端·javascript·笔记
炫饭第一名3 小时前
🌍🌍🌍字节一面场景题:异步任务调度器
前端·javascript·面试
艾莉丝努力练剑4 小时前
【C++:继承和多态】多态加餐:面试常考——多态的常见问题11问
开发语言·c++·人工智能·面试·继承·c++进阶
Skrrapper4 小时前
【C++】C++11出来之后,到目前为止官方都做了些什么更新?
开发语言·c++
有时间要学习4 小时前
Qt——界面优化
开发语言·qt
丘耳4 小时前
vis-network 知识点笔记
前端·javascript
你说啥名字好呢4 小时前
【React的Fiber及中断-重启逻辑的设计】
javascript·react.js
摘星编程4 小时前
深入 Actix-web 源码:解密 Rust Web 框架的高性能内核
开发语言·前端·rust·actixweb