javascript计时原理

在开始之前,先看一段代码:

setTimeout(function(){

/* Some long block of code… */

setTimeout(arguments.callee, 10);

}, 10);

setInterval(function(){

/* Some long block of code… */

}, 10);

    计时器通过设定一定的时间段(毫秒)来异步的执行一段代码。因为 Javascript 是一个单线程语言,计时器提供了一种绕过这种语言限制来执行代码的能力。

今天就简单的来说下计时器的工作原理。

JavaScript 提供了三个函数来构建和操作计时器

1 var id = setTimeout(fn, delay);

2 var id = setInterval(fn, delay);

3 clearInterval(id); clearTimeout(id);

为了了解计时器的工作原理,有一个概念必须记在心里:时间延迟不能被保证。什么意思,就是说你这样写setTimeout(fn, 500)并不代表fn肯定在500毫秒之后马上就执行,延迟很可能会更长。因为 JavaScript 是单线程语言,所有的异步事件(包括计时器、鼠标事件或者一个 XMLHttpRequest 完成)仅仅当程序执行期间有缺口的时候才会执行,不是你规定了什么时候就什么时候执行,要知道程序员不是万能的,你写的东西最终还是要看浏览器脸色的。


理解了下面这幅图,基本上也就理解的javascript计时器的原理:

javascript计时原理

    程序开始的时候,执行了一段javascript代码段,在这个代码段中,调用了一个timer和一个interval,同时还产生了一个click事件。在大约13秒的时候timer请求执行。但是由于浏览器当前正在执行代码段,因此只有排队。

    大约18毫秒的时候,代码段执行完毕,这时候等待的有click和timer任务。浏览器同学思考了一下,决定让click事件优先相应,于是,click事件开始执行,而timer继续排队。

    20毫秒的时候,interval的第一次请求执行,于是乎,它也进入排队。

    29毫秒的时候,click事件处理完毕,浏览器先给timer开了后门,队列中只留下了孤独的interval,关键的时刻来了。这时候,interval的第二次请求来了,而该interval的第一次请求都尚未被相应。如果浏览器傻乎乎的直接将他排队,那么再执行完timer以后,将连续执行两次interval,这显然与用户规定的10ms执行间隔不符,于是在队列中有上一次未执行的interval任务情况下,浏览器会kill掉新到来的interval任务。

    这样一直执行到第一个interval刚响应完毕的时候,这时候interval第三次请求到来,而这时队列空空如也。于是interval直接执行。虽然两次interval的执行间隔为0ms,但是浏览器也只好如此了。

    

    因此,可以看出interval和timer最大的区别是interval是每隔10ms固定时间提交一下响应请求,而不能保证响应的间隔时间。因为它提交请求和浏览器响应是两码事。而timer是在其代码块执行完毕以后,才提交下一次请求,即timer start。因此:

setTimeout(function(){

/* Some long block of code… */

setTimeout(arguments.callee, 10);

}, 10);

setInterval(function(){

/* Some long block of code… */

}, 10);

这两个函数看起来效果一样,其实不然,第一个代码块总会延迟10毫秒执行,虽然大多时候是大于10毫秒的。而第二个每到10毫秒就尝试执行,不管之前的触发执行了没有。



你可能感兴趣的:(JavaScript,计时器)