在其他文章中经常看到关于setInterval的这类结论:
如果setInterval回调函数的执行时间将足够长(比指定的时间间隔长),它们将连续执行并且彼此之间没有时间间隔。
当setInterval回调函数第二次被触发时(此时setTimeout函数仍在执行)setInterval的第一次触发将被抛弃掉。当一个很长的代码块在执行时,可能把所有的setInterval回调函数都排在执行队列的后面,代码块执行完之后,结果便会是一大串的setInterval回调函数等待执行,并且这些函数之间没有间隔,直到全部完成。所以,浏览器倾向于的当没有更多interval的处理函数在排队时再将下一个处理函数排到队尾(这是由于间隔的问题)。
setInterval不会考虑当前正在执行什么,而把所有的堵塞的函数排到队列尾部。这意味着两次setInterval回调函数之间的时间间隔会被牺牲掉(缩减)。
而我为了验证上述描述,写了一段代码:
var period = 60 * 1000 * 60 * 2
var end
var date = new Date(end)
var interval = 1000
var count = 0
var startTime = new Date().getTime()
console.log('开始时间:' + startTime)
var loop = function () {
count++
if (count === 100) {
var endTime = new Date().getTime()
console.log('结束时间:' + endTime) // 打印开始时间
console.log('时间差毫秒数:' + Number(endTime - startTime) + '对应秒数:' + Number(endTime - startTime) / 1000)
console.log('计时器计算秒数:100')
return clearInterval(Itvid)
}
if (!end) { end = new Date().getTime() + period }
var diff = end - new Date().getTime()
var h = Math.floor(diff / (60 * 1000 * 60))
var hdiff = diff % (60 * 1000 * 60)
var m = Math.floor(hdiff / (60 * 1000))
var mdiff = hdiff % (60 * 1000)
var s = mdiff / (1000)
var roundS = Math.round(s)
var j = 0
while (j<100000000 * 40) { // 放大主线程代码执行时间(大约2s)
j++
}
console.log(h + '小时:', m + '分钟:', s + '秒(精确到毫秒)', roundS + '秒(四舍五入)')
}
var Itvid = setInterval(loop, interval)
得到结果如下:
结果看到计时器还是按照预期执行了100次循环,只是由于代码阻塞的原因,完成100秒计时的实际耗时远超过100s。即使如此,也没有发现上述引用中所描述的两次回调函数的时间间隔被牺牲掉的现象,或是排队中的setInterval事件会连续执行。是上述描述有误,还是我的理解有误?请各位指点迷津。