注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

梦幻雪冰

技在手,能在身,思在脑,从容过生活——陈能堡

 
 
 

日志

 
 

【转载】JavaScript 高级计时器 详细分析  

2014-10-26 13:14:12|  分类: JavaScript |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
JavaScript 高级计时器 详细分析

计时器这个东西,看上去很简单,但是可以拓展挖掘的东西却有很多。对于计时器的基本描述(setInterval与setTimeout)基本名词要规范,如“递归”,文字内容描述应当清晰易于理解,而不是含糊不清。对于区别,并不是仅仅说出运行上的特点,还应当能够说出如何应用以及对性能的影响。对于运行上有可能出现的问题,也能够阐述出来。

平时的基本阐述方式
计时器分为两类,一种是“在间隔设置了的时间之后,运行相应的函数”,即setTimeout,而另一种是“每隔一段设定的时间间隔,就运行一次相应的函数”。我们可以使用将setTimeout的代码放置到函数内,然后通过对函数的递归调用,而实现类似于setInterval的效果。

对于上面阐述方法的“纠偏”
JavaScript的运行是单线程运行,因此,严格意义上来讲,上面的基本阐述当中并不是足够的严谨。应该是说,在运行本行代码的时候,将定时器的代码添加到了运行队列当中,而不是何时执行/运行代码。此时需要等到当前“事件处理程序”运行之后再去执行定时器代码。换句话说,就是,并非是设置的毫秒数后就执行定时器代码,执行的时间是有可能提前/延后的。

理解计时器的延迟和提前
为方便理解,书写一个例子。假设有如下这段函数,如果认为点击事件的处理程序需要运行200毫秒,从函数开始运行直到设置计时器代码,需要花费10毫秒,计时器设置为150毫秒后运行函数功能,那么相当于是在160毫秒的位置设置了定时器代码,而这段在200毫秒的位置才进行了执行。

<script>

     con.onclick = function(){
          // 代码段1
          // 代码段1运行10毫秒
          setTimeout(move, 150);
          // 设置在150毫秒,将计时器中的代码插入到队列当中
          // 代码段2
          // 代码段2需要运行190毫秒(注意,此处把setTimeout这句代码的执行时间假设为0)
     }
     function move(){
          // 假设move函数需要运行100毫秒
     }
</script>
JavaScript 高级计时器 详细分析 - 独行冰海 - 独行冰海
欢迎沟通交流——独行冰海

深入分析setInterval 引擎方面
针对setInterval,JavaScript引擎进行了处理。之所以处理,在于定时器中代码内容的执行时间有可能会大于间隔时间。也就是说,在代码被再次添加到队列之前,还没与完成执行,从而导致连续运行多次。因此,JavaScript引擎进行了相关处理,仅当队列中没有该定时器的任何其他代码实例时,才能够将定时器代码添加到队列。
由于线程方面的因素,如果使用setInterval之后,可能会造成的问题以及问题规避:1)某些间隔会被跳过;——这也就能够解释如果我们将setInterval中的时间间隔设置为1-10,然后通过位置的变化去实现滚动类效果,会发现滚动块不能像我们希望的那么快的运动。2)多个定时器的代码执行之间的间隔可能会比预期的小。
依旧举个例子:
JavaScript 高级计时器 详细分析 - 独行冰海 - 独行冰海

规避问题的方法:

setTimeout(function(){

          // 其他代码
          setTimeout(arguments.callee, interval);
     }, interval);
     // 备注:interval指的是毫秒数。
     // 基本原理是:链式的调用setTimeout,每次函数执行时会创建一个新的定时器,第二个setTimeout调用使用了arguments.callee来获取对当前执行的函数的引用,并为它设置另一个定时器。这样做的好处是,在前一个定时器代码执行完毕之后,不会在队列中加入新的定时器代码,同时还能够没有任何缺失的间隔,从而避免连续运行。callee 属性是 arguments 对象的一个成员,他表示对函数对象本身的引用,这有利于匿名函数的递归或确保函数的封装性
最后扯一扯内存泄露
内联书写setInterval时,由于匿名函数被定义于全局中,不能够计时器的清除,因此很容易造成内存泄露。

总结:
JavaScript引擎是单线程的,强制所有的异步事件排队等待执行。
setTimeout 和 setInterval 在执行异步代码的时候有着根本的不同。
如果一个计时器被阻塞而不能立即执行,它将延迟执行直到下一次可能执行的时间点才被执行(比期望的时间间隔要长些)。
如果setInterval回调函数的执行时间将足够长(比指定的时间间隔长),它们将连续执行并且彼此之间没有时间间隔。

欢迎沟通交流——独行冰海
  评论这张
 
阅读(106)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017