← 返回题目列表

如何手写 sleep 函数?它和 setTimeout 有什么关系?

简单 第 18 / 27 题 更新于 2026/07/29
手写代码PromisesetTimeout异步

简化版

sleep 是把 setTimeout 包装成 Promise,让代码可以用 await sleep(ms) 暂停一段时间。它不会阻塞线程,只是让当前 async 函数后续逻辑延后执行。常用于重试延迟、动画间隔、测试等待和节流调度。边界包括:定时器不精确、需要支持取消、不要把它理解成同步阻塞。

详细版

基础版本非常短:

function sleep(ms: number) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

await sleep(1000)
console.log('1 秒后执行')
说明
底层仍然是 setTimeout
返回Promise
阻塞不阻塞主线程
用法配合 await 写出顺序感

sleep 只是延后 async 函数继续执行,不会让 JavaScript 主线程“睡眠”。

完整版教学

一、sleep 的本质

JavaScript 没有真正的同步 sleep,因为主线程如果被阻塞,页面渲染和用户交互都会卡住。

前端里的 sleep 通常是 Promise 包装:

const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))

它让异步代码写起来像同步流程,但底层仍是事件循环。

二、为什么不会阻塞线程

调用 await sleep(1000) 时,当前 async 函数暂停,控制权交回事件循环。浏览器仍可以处理渲染、点击和其他任务。

1 秒后,定时器回调进入任务队列,Promise resolve,后续代码作为微任务继续执行。

三、常见使用场景

sleep 常用于这些地方:

  • 请求失败后延迟重试。
  • 测试中等待异步状态稳定。
  • 分批处理任务时让出主线程。
  • 演示动画或步骤流程。
for (const item of list) {
  process(item)
  await sleep(16)
}

分批处理时它可以避免长时间连续占用主线程。

四、定时器不精确

setTimeout(fn, 1000) 不代表精确 1000ms 后一定执行。它表示至少等待约 1000ms,真正执行还要看主线程是否空闲、浏览器节流策略和任务队列。

后台标签页中,浏览器还可能降低定时器频率。

五、如何支持取消

可以结合 AbortSignal

function sleepWithSignal(ms: number, signal?: AbortSignal) {
  return new Promise<void>((resolve, reject) => {
    if (signal?.aborted) return reject(signal.reason)
    const timer = setTimeout(resolve, ms)
    signal?.addEventListener('abort', () => {
      clearTimeout(timer)
      reject(signal.reason)
    }, { once: true })
  })
}

取消能力在重试、轮询和页面卸载时很有用。

六、和忙等待的区别

错误做法是用循环卡时间:

while (Date.now() - start < 1000) {}

这会阻塞主线程,页面无法响应用户操作。前端不要这样实现 sleep。

七、常见误区与追问

  • 误区:sleep 会让线程暂停。 Promise sleep 只是延后当前 async 函数,主线程仍然能处理其他任务。
  • 误区:setTimeout 时间绝对精准。 定时器只能保证大约延后,主线程忙时会继续延迟。
  • 误区:sleep 可以解决竞态问题。 固定等待只是脆弱兜底,正确做法是等待明确事件或状态。
  • 追问:如何实现可取消 sleep? 保存 timer,收到 AbortSignal 后 clearTimeout 并 reject。
  • 追问:sleep 后的代码属于宏任务还是微任务? 定时器回调是宏任务,Promise resolve 后 await 后续作为微任务继续。
  • 追问:为什么不能用 while 忙等? 它会占满主线程,导致页面卡死。

八、加强记忆

sleep 记成“setTimeout 的 Promise 外衣”。它让 async 代码更顺,但不阻塞线程、不保证精确时间;工程版本最好支持取消。