JavaScript 中 setTimeout 会产生双倍时间间隔

2016-08-24 10:04:27 +08:00
 hansnow

代码如下

var testDelay = function testDelay (interval) {
    setTimeout(function () {
        console.log(new Date().getSeconds())
        setTimeout(arguments.callee, interval)
    }, interval)
}

testDelay(1000)

控制台输出如下

预想的效果是每隔 1s 进行一次输出,但是实际效果却是时间间隔变成了 2s ,请问这是为什么呢?

3114 次点击
所在节点    问与答
23 条回复
newghost
2016-08-24 10:11:01 +08:00
为毛我这里是一秒一个?

var testDelay = function testDelay (interval) {
setTimeout(function () {
console.log(new Date().getSeconds())
setTimeout(arguments.callee, interval)
}, interval)
}

testDelay(1000)
undefined
VM635:3 36
VM635:3 37
VM635:3 38
VM635:3 39
VM635:3 40
VM635:3 41
VM635:3 42
VM635:3 43
shiye515
2016-08-24 10:13:43 +08:00
原因就是你电脑太卡了,执行 console.log 也要+1s
hansnow
2016-08-24 10:15:03 +08:00
@newghost what????这我就更想不明白了啊。。。
Chrome 版本: 51.0.2704.84 m (64-bit)
Windows 版本: Microsoft Windows [版本 10.0.10586]
FrankFang128
2016-08-24 10:16:54 +08:00
你没懂 setTimeout
它不保证准时的
hansnow
2016-08-24 10:18:20 +08:00
@shiye515 应该不是这样吧?下面的代码就可以输出两个相邻的数字

```javascript
var testDelay = function testDelay (interval) {
console.log(new Date().getSeconds())
setTimeout(function () {
console.log(new Date().getSeconds())
}, interval)
}

testDelay(1000)
```
hansnow
2016-08-24 10:20:36 +08:00
@FrankFang128 这个我稍微知道一点, setTimeout 只是把代码加入了执行队列。但是前面只有一个 console.log 额。。。打个 log 出来应该不会消耗 1s 的时间吧,而且你看我在#5 贴的代码,是可以输出两个连续的数字的,说明 console.log 没消耗 1s 的时间
UnisandK
2016-08-24 10:22:03 +08:00
zzNucker
2016-08-24 10:25:38 +08:00
重新启动浏览器。
笔记本请插上电源用高性能模式。。

虽然我觉得省电模式也不可能 2000ms 一个 tick
lwbjing
2016-08-24 10:26:24 +08:00
var testDelay = function testDelay (interval) {
setTimeout(function () {
console.log(new Date().getSeconds())
setTimeout(arguments.callee, interval)
}, interval)
}

testDelay(1000)
undefined
VM139:3 53
VM139:3 54
VM139:3 55
VM139:3 56
VM139:3 57
VM139:3 58
VM139:3 59
VM139:3 0
VM139:3 1
VM139:3 2
hansnow
2016-08-24 10:28:18 +08:00
@newghost
@FrankFang128
@UnisandK
@zzNucker

我已经凌乱了,把 interval 改成 1s 以上的话是正常的,然后我又试着改到了 100ms ,结果就是下面这样的输出。。。这也太看心情了吧。。。

exoticknight
2016-08-24 10:36:38 +08:00
在 MDN 上查到 “ Timeouts in inactive tabs clamped to >=1000ms ”
然后我也看到本身是 1s 一次的输出的确会变成 2s
+1s
xxxyyy
2016-08-24 10:37:50 +08:00
你把毫秒也打印出来一看就清楚了,比如上一次是 1.999 ,那下一次有可能是 3.100 ,毕竟这个并不是很准的。
mdluo
2016-08-24 10:39:21 +08:00
没有仔细看代码,但是感觉这个应该是 Chrome 调试工具的 Bug ,我之前也遇到过类似的问题,打断点输出和不打断点输出的结果不一致,升级到 Chrome 52 就好了(我在 Chrome 52 里跑了一下是正常的 1 秒输出一次)
mdluo
2016-08-24 10:46:39 +08:00
至于 @FrankFang128 说的不准时, setTimeout 确实会不准时,但是不至于误差到秒级别。这个应该跟代码的执行顺序有关系,看调试工具怎么判断 console.log 的输出和执行 setTimeout 回调之间的先后顺序

没仔细看代码,欢迎打脸
subpo
2016-08-24 10:52:02 +08:00
少掉的一秒到哪里去了呢?
exoticknight
2016-08-24 10:54:54 +08:00
@subpo
通常来说,是被前面的代码执行挤掉了
或者说是被……
66beta
2016-08-24 10:56:00 +08:00
setTimeout 不精准,但这个个案来看,就是楼主机器太卡 XD
dacapoday
2016-08-24 10:56:26 +08:00
这哪是 bug,你也知道是添加到队列而不是中断触发事件,浏览器除了 JS 就不干其他活了?这种情况应该用 requestAnimationFrame
shenxian
2016-08-24 11:00:11 +08:00
+1s
FrankFang128
2016-08-24 12:59:01 +08:00
自己看 MDN
浏览器执行 setTimeout 是看心情的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/301381

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX