You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么JavaScript的setInterval()执行时毫秒数会持续递增?

为什么setInterval执行时毫秒数会持续递增?

测试代码

console.log('before', new Date().toLocaleString(), new Date().getMilliseconds())
setInterval(() => {
    console.log(new Date().toLocaleString(), new Date().getMilliseconds());
}, 1000);

实际输出

before 7/27/2023, 9:06:14 PM 364
7/27/2023, 9:06:15 PM 367
7/27/2023, 9:06:16 PM 370
7/27/2023, 9:06:17 PM 372
7/27/2023, 9:06:18 PM 376
7/27/2023, 9:06:19 PM 378
7/27/2023, 9:06:20 PM 382

疑问

为什么每次执行时毫秒数都会持续增加?我知道函数加入调用栈会有一定的毫秒抖动,但抖动不应该每次都累加在上一次的执行时间上,为什么输出不能是时而抖动时而稳定的情况,比如:

before 7/27/2023, 9:06:14 PM 364
7/27/2023, 9:06:15 PM 367
7/27/2023, 9:06:16 PM 367
7/27/2023, 9:06:17 PM 367
7/27/2023, 9:06:18 PM 368
7/27/2023, 9:06:19 PM 367
7/27/2023, 9:06:20 PM 367

解答

核心原因在于JavaScript中setInterval的调度逻辑:

  • setInterval的调度是基于初始计划时间点的,第一次执行计划是在调用它的时间+指定间隔(这里是1000ms),之后每一次的计划执行时间,都是上一次的计划时间再加1000ms,而不是以上一次实际执行完成的时间为基准。

  • 但JavaScript是单线程模型,主线程一旦被其他任务(比如页面渲染、其他脚本执行、浏览器后台操作)占用,定时器的回调就只能排队等待调用栈空闲。举个例子:

    1. 初始调用时间是T,第一次计划执行时间是T+1000ms,但实际因为主线程繁忙,回调在T+1003ms才完成执行;
    2. 下一次计划执行时间依然是T+2000ms,但实际执行时主线程可能又有任务,只能在T+2006ms左右执行;
    3. 以此类推,每次实际执行时间都比计划时间晚一点,毫秒数自然就持续递增了。
  • 你期望的“时而抖动时而稳定”的情况,需要每次延迟的时间刚好被后续调度“抵消”,但浏览器的定时器精度、主线程的任务队列状态都是不可控的,多数情况下延迟只会累积,不会自动回补。

如果需要更精准的定时,可以放弃setInterval,改用递归调用setTimeout:每次执行回调时,计算下一次应该执行的时间(比如用当前时间+1000ms),再设置新的setTimeout,这样能尽可能减少延迟累积的问题。

内容的提问来源于Stack Exchange,提问作者Jemish Virani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:57:59