美文网首页
关于setInterval的坑

关于setInterval的坑

作者: 陈学谦_ | 来源:发表于2017-04-18 21:57 被阅读1331次

20170418


在参加360面试的时候面试官问到了这样的一道题:
“setInterval和setTimeout有什么区别”

我当时只说出了最基本的区别——一个是倒计时,一个是循环。面试官一脸淫荡的看着我说:“如果setInterval计时器的回调函数执行完需要5秒,而计时器时间间隔为3秒,那会发生什么?”

嘿呀,我居然没想到这一点,但凭借我扎实的JS功底,这点对我来说不是小事。我告诉他那下一次循环就会插入到队列中,等待着此次循环执行完后再执行。

面试官又是一脸淫荡地看着我,“其实并不会,如果之前的代码还没有执行完,那他就会跳过这次循环,再等3秒执行下一次循环。”

将他说的话整理一下应该是下面这样:

0s..............................第一次添加定时器
3s..............................第一次执行定时器代码,并且第二次添加定时器
6s..............................第二次执行定时器代码失败,跳过此次循环,再次添加第二次定时器
8s..............................执行完第一次定时器代码
9s..............................第二次执行定时器代码,并且第三次添加定时器
12s............................第三次执行定时器代码失败,跳过此次循环,再次添加第三次定时器
14s............................执行完第二次定时器代码

“如果之前回调没有执行完,则不能再次执行当前回调,因此会跳过此次回调”

被面试官鄙视了一番,很沮丧。面试官告诉我在《高程3》中写有这部分的内容,让我回去好好看。

回来我就看了一下这部分内容,具体位置在P610的“22.3.1 重复的定时器”,书上是这么说的:

当使用setInterval()时,仅当没有该定时器的任何其他代码示例时,才将定时器代码添加到队列中。这确保了定时器代码加入到队列中的最小时间间隔为指定间隔

今天还和小伙伴们讨论了一番,但我发现我有点误解这段话的意思。

有几个关键词——定时器代码、队列

其实就是说,当我定时器到了指定时间后,要执行这一波代码时,如果上一波定时器代码还没有完全执行完的话,我就不会执行我这一波代码,也不会将他加入到队列中排队,而是调到下一波倒计时

看来面试官没蒙我,但是想起他那淫荡的表情我又有些不敢相信,于是我自己做了次试验。

程序滞留固定时间的方法如下:

function sleep(time) {
  let startTime = window.performance.now();
  while (window.performance.now() - startTime < time) {}
}

活学活用,window.performance.now()能更精确的获取时间

运行代码如下:

let count = 1;
let getTime = window.performance;
let startTime = getTime.now();

setInterval(function () {
  console.log(`第${count}次开始 ${getTime.now() - startTime}`); // 显示开始时间
  sleep(500); // 程序滞留500ms
  console.log(`第${count}次结束 ${getTime.now() - startTime}`); // 显示结束时间
  count += 1;
}, 300); // 300ms间隔

Chrome57中运行结果:

Paste_Image.png

我擦,说好的跳过呢?这结果不就是我当初所认为的那个结果吗?
多试几个浏览器

FireFox47:

Paste_Image.png

Opera:

Paste_Image.png

以及最垃圾的IE:
IE代码要改下:(毕竟IE)

setInterval(function () {
  console.log('第' + count + '次开始 ' + (getTime.now() - startTime));
  sleep(500);
  console.log('第' + count + '次结束 ' + (getTime.now() - startTime));
  count += 1;
}, 300);
Paste_Image.png

好嘛,连人家IE都不配合。

难道是浏览器实现时和标准有差别?

三、Node

我又在Node上试了一下,虽然都是V8引擎:

月影老师说:
“定时器任务什么时候放到队列里面是浏览器管理的,而队列里面的任务什么时候执行是引擎处理的”
这里的引擎指的是node或者浏览器内核
“V8是ES引擎,实现的只是ECMA-262部分,timer并不是ECMAScript部分”

这里我还要深究一下...

Paste_Image.png

哇塞,良心啊,居然都能保持300ms的间隔

目前得出的结论:
1. 标准中,setInterval()如果前一次代码没有执行完,则会跳过此次代码的执行。
2. 浏览器中,setInterval()如果前一次代码没有执行完,不会跳过此次代码,而是将其插在队列中,等待前一次代码执行完后立即执行。
3. Node中,setInterval()会严格按照间隔时间执行。

具体原因是什么我还在探索中。

相关文章

网友评论

      本文标题:关于setInterval的坑

      本文链接:https://www.haomeiwen.com/subject/fviqzttx.html