javascript - 关于 setInterval 执行机制
过去多啦不再A梦
过去多啦不再A梦 2017-05-19 10:35:06
0
2
656

//更新:这个问题没参考意义,有点脑抽,已经申请关闭。具体可以看下面我的回答

前两天看到一篇博客中提到:如果 setInterval 回调函数的执行时间大于规定的延迟时间,定时器被触发时如果任务队列有同一个定时器的回调函数,那么这次的回调就会被忽略,意思是任务队列中不会有两个及以上同一个定时器的回调函数。语句表达不清,直接看代码吧:

例子1

(function(){
    var j=1;
    var start=new Date().getTime();
    var timr=setInterval(function(){
        console.log("第"+j+"次定时器开始时间:"+(new Date().getTime()-start));
        for(var i=0;i<5000;i++){console.log("")};
        console.log("第"+j+"次定时器结束时间:"+(new Date().getTime()-start));
        j++;
    },100);
    setTimeout(function(){
        clearInterval(timr)
    },1000)
})()

setInterval 每隔 100ms 往任务队列添加函数,在 1000ms 之后 setInterval 被清除。按照上面的说法来解释这个结果:

  1. 100ms 时把第一个 for 循环放入任务队列,空闲的主线程开始执行这个循环,耗时 863ms;

  2. 在第一个 for 循环执行期间,第 200ms 的时候第二次定时器被触发,第二个 for 循环被放入空的任务队列,直到 964ms之后主线程空闲开始执行第二个 for 循环;

  3. 第三次到第八次定时器(理论上的序号)被触发时,主线程在执行第一次 for 循环,任务队列中有第二个 for 循环,所以这些函数被忽略,没有进入任务队列;

  4. 900ms 时,第九个定时器被触发,主线程在执行第二个 for 循环,任务队列中不存在这个定时器的函数,所以这个定时器的函数被放入任务队列,也就是结果中的“第3次定时器”;

  5. 1000ms 时,第十个定时器被触发,由于第三条一样的原因被忽略,之后 setInterval 被清除。

例子2

不过另一个例子测试的结果却不是这样

for(var i=0;i<10000;i++){
    console.log(1)
}
setInterval(function(){
    console.log("定时器")
},1000)

浏览器先执行 for 循环,我电脑上执行了 13s 左右(电脑好差啊。。。),按照上面的说法,在这 13s 的时间内,任务队列中只会存在一个这个定时器的函数,然后运行结果是在 13s 之后同时打印出 13 个“定时器”,然后再以一秒为周期执行函数。

问题

上面两个例子是冲突的,setInterval 在这种情况下是怎么进行工作的?希望能给个清晰的答案,最好带有权威资料的。谢谢大噶。

过去多啦不再A梦
过去多啦不再A梦

全部回复(2)
Ty80

这个问题是我问的,现在发现有点脑抽。。。
第二个例子中,for 循环执行过程中 js 线程一直被占用,下面的语句还没有被解析,也就是定时器还没有被注册。把例子修改一下加上执行时间:

var start=new Date().getTime();
for(var i=0;i<10000;i++){
    console.log(1)
}
console.log("耗时"+(new Date().getTime()-start))
setInterval(function(){
    console.log("定时器"+(new Date().getTime()-start))
},1000)

用这个例子进行测试就很明白了。 上面的 for 循环执行了 1544ms 左右,这个时候 js 线程解析之后的语句,定时器被注册,然后正常执行。

所以两个例子并没有任何冲突的地方,第一个例子是对的,当主线程在执行定时器的函数,而且任务队列有同一个定时器的函数时,在这期间这个定时器所有的触发都会被忽略。

巴扎黑

但是,例 2 for 在结束前,setInterval 并没有被执行啊

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板