一、Timer
在js里面提供了两个用来定时执行代码的函数:setTimeout和setInerval,统称为Timer.
二、初级印象
setTimeout( func|string, time )在一定时间后执行代码
setInterval( func|string, time)每隔一段时间后执行代码
三,参数解析
(一)、func | string
1,这两个计时器都可以接收一个函数对象或者一段字符串,
当接收字符串的时候,会通过eval()函数进行解析,
而在执行时,不管是函数对象还是解析后的字符串,此时的上下文都是window
图3-1
数字为setTimeout产生的计时器id,通过打印的window可知,此时函数执行的上下文为window。
2,新版浏览器允许在time后继续接收参数,并传入func,
考虑向下兼容,可以通过
func.call( undefined, arg1, arg2...)或者
func.apply( undefined, [arg1, arg2...])来实现
(二)、time
1,添加的时机
js是单线程、异步执行的,其事件处理机制叫做event loop。
当js引擎遇到setTimeout、setInterval、或者外部事件触发等,会通知不同的线程去操作,完成后往事件队列末尾添加任务,等待js引擎的顺序执行。
图3-2,来自这里
所以,Timer的正确理解应该是:
在/每隔一定时间,将该任务添加到事件队列末尾
2,带来的影响
由于任务队列的不确定性,永远无法保证按照设定的时机执行任务!
图3-3
图3-4
四、setInterval本身的缺陷
通过上面分析知道,setInterval是每隔一定时间往事件队列末尾添加任务,扣掉事件本身的执行时间,从上一个事件结束到下一个事件开始的事件差,永远小于设定的time,此时可以通过setTimeout进行改进。
原来的setInterval( func, time )可以变为
var temp = setTimeout( function() {
func();
setTimeout(temp, time);
}, time);
temp();
当然,这是在假设了期间不再有新的事件加入的前提下
五、清除Timer
每次setTimeout或者setInterval,都会产生一个唯一的计时器id,通过清理该id即可以清理相应的计时事件。
本来各自对应的clearTimeout和clearInterval,竟然可以混用!
图5-1
图5-2
参考文献:
1,http://www.cnblogs.com/fly-snow/archive/2016/04/24/5427865.htm
2,http://www.open-open.com/lib/view/open1452474629745.html