首页 > 解决方案 > setInterval 不同于 chrome 和 firefox

问题描述

以下代码在 Firefox 和 Chrome 之间打印不同的结果

var start = Date.now()

var id = setInterval(function interval() {
    var whileStart = Date.now()   
    console.log(whileStart - start)
    while (Date.now() - whileStart < 250) { 
    }
}, 100)

setTimeout(function timeout() {
    clearInterval(id)
    console.log('timeout',Date.now() - start)       
}, 400)

镀铬 74 打印:

100
351
605
timeout 855

火狐 67 打印:

101
351
timeout 601

为什么?

加上 setTimeout 延迟,结果还是不一样。

var start = Date.now()

var id = setInterval(function interval() {
    var whileStart = Date.now()   
    console.log(whileStart - start)
    while (Date.now() - whileStart < 250) { 
    }
}, 100)

setTimeout(function timeout() {
    clearInterval(id)
    console.log('timeout',Date.now() - start)       
}, 500)

标签: javascriptsettimeoutsetinterval

解决方案


这是因为Chrome 的实现setInterval确实纠正了每次调用之间的偏差。因此,与其在间隔回调结束时盲目地再次setTimeout(fn, 250)调用,它实际上是setTimeout(fn, max(now - 250, 0)).

所以这给了

t    Firefox (no drift control)   |   Chrome (drift control)

     ––––––––––––––––––––––––––––––––––––––––––––––––––––––––

0    schedule interval @100ms         schedule interval @100ms
0    schedule timeout  @400ms         schedule timeout  @400ms


100  exec interval callback           exec interval callback
     => block 250ms                   => block 250ms
     ...                              ...
350  schedule interval @450ms         schedule interval @350ms
       (now + 100ms)                    (now + max(100ms - 250ms, 0))
350                                   exec interval callback
                                      => block 250ms
400  exec timeout callback            ...
       => cancel interval             ...
                                      ...
600                                   schedule interval @600ms
                                      exec interval callback
                                      => block 250ms
                                      ...
850                                   schedule interval @850ms
                                      exec timeout callback
                                        => cancel interval

请注意,最后一个间隔@600实际上取决于哪个timeoutinterval首先安排的时间。

还要注意 Chrome 的行为可能在不久的将来成为标准:https ://github.com/whatwg/html/issues/3151


推荐阅读