secrets of the javascript Ninja( javascript Timer)(javascript忍者的秘密)

javascript中定时器是如何工作的

     计时器(定时器)是一个大家常常不能够充分理解,并且常常被误用的JavaScript的特性之一,使用计时器能够开发非常复杂的动态效果,它具有在一段时间后异步执行一段代码的能力,由于JavaScript天生是单线程的,但是使用计时器能够打到异步执行一段代码的能力。

 

 

    从根本上理解定时器是如何工作的是非常重要的,由于它是单线程运作,定时器如何运作并不是太明了,下面我们通过一下三个方法,来看看它到底是如何执行的,这三个方法能够形成和操作计时器:

var id = setTimeout(fn, delay);该方法初始化一个单独的计时器,用于在delay指定的时间后调用fn函数,该方法会产生一个唯一的ID,稍后可以使用该ID取消该计时器

 

var id = setInterval(fn, delay); 该方法和上面的方法类似,他会在每隔delay指定的时间后都会都会执行fn函数,也会产生一个唯一的ID,用于取消定时器。

 

clearInterval(id);, clearTimout(id);接受上述两个函数返回的ID,停止定时器调用上面两个函数中的第一个参数。

 

 

     为了理解定义器内部是如何工作的,有一个重要的概念我们需要理解:定时器延迟时间并不能保证。因为所有的JavaScript在浏览器中执行一个单线程的异步事件时,只有当有一个入口时才能开始执行。

      通过下图,我们能够更好的理解这个原因:

JavaScript定时器示例图

 

       在这个示例中有很多信息可以挖掘,但是完全理解了之后你将会更清楚地认识到异步的JavaScript是怎么执行的。这是个一维的图:竖直方向上的是(挂钟式)时间,单位为毫秒。蓝色的框表示正在执行的JavaScript片段。举例来说,第一块JavaScript执行了约18ms,而鼠标点击则执行了约11ms,以此类推。

 


 

       由于JavaScript向来都只能在同一时间执行一块代码(这是由它单线程的本质决定的),所以每一个代码块都“阻塞”了其他的异步事件。这意味着当异步事件发生时(比如鼠标点击、timer触发或者是XMLHttpRequest完成),这些事件将进入到一个队列中等待执行(队列的实现方法因浏览器而异,我们在此只讨论一个简化的情况)。

 

      首先,在第一个JavaScript块中,有两个timer被初始化了:一个10ms的setTimeout和一个是10ms的setInterval。由于timer(这里的timer指setTimeout中的 timer,而下文中的interval则指setInvertal中的timer)开始的时间,实际上它在第一个代码块结束前就已经触发了。然而请注意,它并不会马上执行(事实上由于单线程的存在,它也无法做到马上执行)。相反的,这个被延期执行的函数进入队列中,等待在空闲的时候被执行。

 

     在第一个JavaScript块中,我们看到一个鼠标点击事件也发生了。而与这个异步事件(我们不知道用户什么时候会去执行一个动作,因此将其认为是一个异步动作)相关的JavaScript回调函数也无法立马执行,正如timer一样,它也进行到队列中等待被执行。

 

     当第一个JavaScript块被执行完之后,浏览器问了一个问题:有正在等待被执行的代码吗?在这个例子中,鼠标点击事件和time事件都正在队列中等待。于是浏览器选了一个(鼠

标点击事件),然后马上执行它。而timer只能继续等下去。

 

     注意当鼠标点击事件正在执行的时候第一次的interval事件也触发了,与timer一样,它的事件也进入队列等待之后执行。然而,注意,当interval再次触发的时候(这个时候timer的事件正在执行),这一次它的事件被丢弃了。如果你在一个大的JavaScript代码块正在执行的时候把所有的interval回调函数都囤起来的话,其结果就是在JavaScript代码块执行完了之后会有一堆的interval事件被执行,而执行过程中不会有间隔。因此,取代的作法是浏览器情愿先等一等,以确保在一个interval进入队列的时候队列中没有别的interval。

 

    事实上,我们可以在例子中看出:当第三个interval触发的时候这个interval自身正在执行。这告诉我们一个重要的事实:interval是不管当前在执行些什么的,在任何情况下它都会进入到队列中去,即使这样意味着每次回调之间的时间就不准确了。

 

 

    最后,当第二个interval回调执行完后,我们可以看到队列已经被清空,没有什么需要JavaScript引擎去执行的了。这表明浏览器现在等待一个新的异步事件发生。于是在50ms的

时候我们看到interval又触发了。这一样,由于没有什么东西挡住了它的执行,它马上就触发了。

 

   让我们来看一个例子,这个例子更好地阐释了setTimeout和setInveral之间的区别。

 

 

 

     乍看上去,这两段代码在功能上似乎是相同的,可实际上并非如此。setTimeout的代码在前一次的回调执行完后总是至少会有10ms的延时(有可能会更多,但是绝对不会更少);而setInterval则总是在每10ms的时候尝试执行一次回调,它不管上一次回调是什么时候执行的。

      我们在此学到了很多,让我们重述一下:


    * JavaScript引擎只有一个线程,这使得异步事件必需列队等待执行。

    * setTimeout和setInterval在如何执行代码上有着本质地区别。

    * 如果一个timer在将要执行的时候被阻塞,它将会等待下一个时机(比预期的延时长)。

    * 如果interval的执行时间较长(比指定的延时长),那么它们将连续地执行而没有延时。

什么地方使用JavaScript定时器

  1. 大量处理dom时,我们可以采用分步加载的办法。

      我们通过下面的代码理解这种用法:

      

  1. 中央定时器控制

当大量使用定时器时,我们该如何管理这些定时器,这种情况在动画处理中尤其重要,因为需要同时处理大量的属性,所以需要一种方案管理这些。

 

 

通过使用这样一个定时器,我们可以了解到一下一个好处:

 

1.在同意时间一个页面上只有一个定时器在执行。

2.你可以根据你的意志暂停或者重新开始定时器。

3.你可以频繁的处理删除的回调函数。

下面来看看如果使用这个中央定时控制器:

 

 

 

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值