仔细认识setInterval
参照http://www.w3cplus.com/javascript/javaScript-setInterval.html
作为拥有广泛应用场景(定时器,轮播图,动画效果,自动滚动等等),而又充满各种不确定性的这setInterval()
,自当先洞悉它,才能很好的驾驭它
setInterval()
函数的用法与setTimeout()
完全一致,区别仅仅在于setInterval()
指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行。
如果网页不在浏览器的当前窗口(或tab),许多浏览器限制setInteral()
指定的反复运行的任务最多每秒执行一次。
setInterval()
指定的是“开始执行”之间的间隔,并不考虑每次任务执行本身所消耗的事件。因此实际上,两次执行之间的间隔会小于指定的时间。比如,setInterval()
指定每100ms
执行一次,每次执行需要5ms
,那么第一次执行结束后95
毫秒,第二次执行就会开始。如果某次执行耗时特别长,比如需要105
毫秒,那么它结束后,下一次执行就会立即开始.
1 var i = 1; var timer = setInterval(function() { alert(i++); }, 2000);
上面代码每隔2000
毫秒,就跳出一个alert
对话框。如果用户一直不点击“确定”,整个浏览器就处于“堵塞”状态,后面的执行就一直无法触发,将会累积起来。举例来说,第一次跳出alert
对话框后,用户过了6000
毫秒才点击“确定”,那么第二次、第三次、第四次执行将累积起来,它们之间不会再有等待间隔。
为了确保两次执行之间有固定的间隔,可以不用setInterval()
,而是每次执行结束后,使用setTimeout()
指定下一次执行的具体时间。上面代码用setTimeout()
,可以改写如下。
var i = 1; var timer = setTimeout(function() { alert(i++); timer = setTimeout(arguments.callee, 2000); }, 2000);
上面代码可以确保两次执行的间隔是2000
毫秒。
根据这种思路,可以自己部署一个函数,实现间隔时间确定的setInterval()
的效果。
function interval(func, wait) { var interv = function() { func.call(null); setTimeout(interv, wait); }; setTimeout(interv, wait); } interval(function() { console.log(2); }, 1000);
上面代码部署了一个interval()
函数,用循环调用setTimeout()
模拟了setInterval()
。
HTML 5标准规定,setInterval()
的最短间隔时间是10
毫秒,也就是说,小于10
毫秒的时间间隔会被调整到10
毫秒。
setInterval()
的运行机制是,将指定的代码移出本次执行,等到下一轮Event Loop
时,再检查是否到了指定时间。如果到了,就执行对应的代码;如果不到,就等到再下一轮Event Loop
时重新判断。这意味着,setTimeout()
指定的代码,必须等到本次执行的所有代码都执行完,才会执行。
setInterval(function() { console.log(2); }, 1000); (function() { sleeping(3000); })();
上面的第一行语句要求每隔1000
毫秒,就输出一个2
。但是,第二行语句需要3000
毫秒才能完成,请问会发生什么结果?
结果就是等到第二行语句运行完成以后,立刻连续输出三个2
,然后开始每隔1000
毫秒,输出一个2
。也就是说,setIntervel()
具有累积效应,如果某个操作特别耗时,超过了setInterval()
的时间间隔,排在后面的操作会被累积起来,然后在很短的时间内连续触发,这可能或造成性能问题(比如集中发出Ajax请求)。
对于setInterval()
得使用,个人建议是能不用尽量不用。涉及到必须要的定时器,前文已经叙述可以使用两个setTimeout()
嵌套组合来实现,并且还能规避掉一些问题得发生。涉及到要用它来制作动画( jQuery就使用setInterval()
来写动画,也是导致其慢原因之一),更建议使用requestAnimationFrame
(RAF),或者直接采用CSS来写(如果可以的话)。
requestAnimationFrame
比起setTimeout()
、setInterval()
的优势主要有两点:
requestAnimationFrame
会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60
帧。- 在隐藏或不可见的元素中,
requestAnimationFrame
将不会进行重绘或回流,这当然就意味着更少的的CPU,GPU和内存使用量。
总结了下,尽量用setTimeout代替setInterval,因为其有累积效应