代码如下
var testDelay = function testDelay (interval) {
setTimeout(function () {
console.log(new Date().getSeconds())
setTimeout(arguments.callee, interval)
}, interval)
}
testDelay(1000)
控制台输出如下
预想的效果是每隔 1s 进行一次输出,但是实际效果却是时间间隔变成了 2s ,请问这是为什么呢?
从楼下各位的回复来看,setTimeout的行为确实有些随机性的。《JavaScript高级程序设计(第三版)》的第22章里面说,“关于定时器要记住的最重要的事情是,指定的时间间隔表示何时将定时器的代码添加到队列,而不是合适实际执行代码”。
一个比较实际的例子是,用这个代码实现toast效果时,当执行下面这个语句时
setTimeout(function(){ x.className = x.className.replace("show", ""); }, 3000);
由于setTimeout的不确定性,在很多移动端浏览器上可能会出现fadeOut动画的结尾出现闪烁的现象。
1
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 |
2
shiye515 2016-08-24 10:13:43 +08:00
原因就是你电脑太卡了,执行 console.log 也要+1s
|
3
hansnow OP @newghost what????这我就更想不明白了啊。。。
Chrome 版本: 51.0.2704.84 m (64-bit) Windows 版本: Microsoft Windows [版本 10.0.10586] |
4
FrankFang128 2016-08-24 10:16:54 +08:00
你没懂 setTimeout
它不保证准时的 |
5
hansnow OP @shiye515 应该不是这样吧?下面的代码就可以输出两个相邻的数字
```javascript var testDelay = function testDelay (interval) { console.log(new Date().getSeconds()) setTimeout(function () { console.log(new Date().getSeconds()) }, interval) } testDelay(1000) ``` |
6
hansnow OP @FrankFang128 这个我稍微知道一点, setTimeout 只是把代码加入了执行队列。但是前面只有一个 console.log 额。。。打个 log 出来应该不会消耗 1s 的时间吧,而且你看我在#5 贴的代码,是可以输出两个连续的数字的,说明 console.log 没消耗 1s 的时间
|
7
UnisandK 2016-08-24 10:22:03 +08:00
|
8
zzNucker 2016-08-24 10:25:38 +08:00
重新启动浏览器。
笔记本请插上电源用高性能模式。。 虽然我觉得省电模式也不可能 2000ms 一个 tick |
9
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 |
10
hansnow OP @newghost
@FrankFang128 @UnisandK @zzNucker 我已经凌乱了,把 interval 改成 1s 以上的话是正常的,然后我又试着改到了 100ms ,结果就是下面这样的输出。。。这也太看心情了吧。。。 |
11
exoticknight 2016-08-24 10:36:38 +08:00
在 MDN 上查到 “ Timeouts in inactive tabs clamped to >=1000ms ”
然后我也看到本身是 1s 一次的输出的确会变成 2s +1s |
12
xxxyyy 2016-08-24 10:37:50 +08:00 via Android
你把毫秒也打印出来一看就清楚了,比如上一次是 1.999 ,那下一次有可能是 3.100 ,毕竟这个并不是很准的。
|
13
mdluo 2016-08-24 10:39:21 +08:00
没有仔细看代码,但是感觉这个应该是 Chrome 调试工具的 Bug ,我之前也遇到过类似的问题,打断点输出和不打断点输出的结果不一致,升级到 Chrome 52 就好了(我在 Chrome 52 里跑了一下是正常的 1 秒输出一次)
|
14
mdluo 2016-08-24 10:46:39 +08:00
至于 @FrankFang128 说的不准时, setTimeout 确实会不准时,但是不至于误差到秒级别。这个应该跟代码的执行顺序有关系,看调试工具怎么判断 console.log 的输出和执行 setTimeout 回调之间的先后顺序
没仔细看代码,欢迎打脸 |
15
subpo 2016-08-24 10:52:02 +08:00
少掉的一秒到哪里去了呢?
|
16
exoticknight 2016-08-24 10:54:54 +08:00
|
17
66beta 2016-08-24 10:56:00 +08:00
setTimeout 不精准,但这个个案来看,就是楼主机器太卡 XD
|
18
dacapoday 2016-08-24 10:56:26 +08:00
这哪是 bug,你也知道是添加到队列而不是中断触发事件,浏览器除了 JS 就不干其他活了?这种情况应该用 requestAnimationFrame
|
19
shenxian 2016-08-24 11:00:11 +08:00
+1s
|
20
FrankFang128 2016-08-24 12:59:01 +08:00 1
自己看 MDN
浏览器执行 setTimeout 是看心情的。 |
21
xujif 2016-08-24 14:47:30 +08:00
是 cpu 降频节能了 chrome 没反应过来?
|
22
lshero 2016-08-24 15:15:56 +08:00
setTimeout 也要按基本法
|
23
ksco 2016-08-24 17:03:24 +08:00
因为某种神秘力量自动给你续了一秒。
|