做为入门者来讲,了解JavaScript中timer的工做方式是很重要的。一般它们的表现行为并非那么地直观,这是由于它们都处在单线程中。让咱们先来看看三个用来出建立和操做timer的函数。javascript
var id = setTimeout(fn, delay);
初始化这个timer,而后这个timer将会在delay延时后调用这个函数fn。这个函数将返回一个惟一的ID,能够经过这个ID来取消timer。java
var id = setInterval(fn, delay);
与setTimeout相似,不过它会持续调用函数fn(每隔delay毫秒),直到timer被取消。
浏览器
clearTimeout(id); clertInterval(id);
接受一个timer的ID,并中止timer的回调事件。
异步
为了理解timer内部工做原理,咱们还须要知道一个重要的概念:timer的延时是不许确的。因为浏览器中的JavaScript在单线程中运行,所以异步事件(如mouse click以及timer)只有在执行期空闲的时候才运行。这个用图表最能解释清楚了,参看下图:
函数
这个图标中有大量的信息能够挖掘,可是彻底理解它将使咱们对JavaScript中异步事件执行原理有个更深的认识。这是一张一维图:数值方向为时间,单位毫秒。蓝色的框表示正在执行的JavaScript片断。举个例子,第一块JavaScript大约执行了18ms,鼠标点击则执行了11ms,以此类推。
spa
因为JavaScript在同一时间只能执行一段代码(由单线程的本质决定),所以每一个代码块都会“阻塞”其余异步事件。这意味着当异步事件发生时(好比鼠标点击、timer触发或者XMLHttpRequest完成),将进入事件队列等待执行(队列的实现方式因浏览器而异,这里只讨论简化的状况)。
线程
从第一段JavaScript代码块开始,有两个timer被初始化了:一个10ms的setTimeout和一个10ms的setInterval。其实在第一段代码块执行完以前timer就已经触发了。注意,不管如何它都不会当即执行(因为单线程缘由,它没法那样作)。相反,这个延时执行的函数进入队列等待下次空闲的时候执行。
code
此外,第一段代码块中鼠标点击事件也发生了。所以和异步事件相关联的回调函数也不能当即执行,像最初的timer同样,也要进入队列等待执行。
blog
最初的代码块执行完之后,浏览器问了这样一个问题:谁在等待执行?这个例子中,鼠标点击事件和timer回调函数都处于等待中。浏览器挑了鼠标点击事件,而后当即执行它。而timer将继续等待下次执行。
队列
注意当鼠标点击事件执行过程当中时,第一次的interval的回调也触发了。和timer同样,它的事件也将进入队列等待执行。而后,当interval再次触发的时候(此时timer正在执行),此次它的事件将被丢弃。若是你在一大块代码执行时,把全部的interval的回调事件排入队列,其结果是在上述代码执行完之后,一推的interval事件将毫无间隔地执行。而浏览器更趋向于等待,以确保interval事件进入队列时没有其余的interval事件。
事实上,从这个例子中能够看出:当第三个interval触发的时候,interval自身正在执行。这告诉咱们一个重要的事实:interval无论当前执行的是什么,都会进入队列,即便这样意味着回调函数之间的时间就不许确了。
最后,当第二个interval事件执行完之后,将没有任何代码留给JavaScript引擎执行。这意味着如今浏览器将等待新的异步事件触发。因而在50ms的时候,interval再一次触发。这一次,没有什么阻塞它的执行,它就当即触发了。
让咱们看一个例子来更好的阐述setTimeout和setInterval之间的区别。
setTimeout(function(){ /*Some long block of code */ setTimeout(argument.callee, 10) }, 10); setInterval(function(){ /*Some long block of code */ }, 10)
咋看一下,这两段代码的功能彷佛是同样的,但实际上并不是如此。尤为是setTimeout这段代码,在前一个回调函数执行完之后,都至少会有10ms的延时(可能会多,但毫不会少)。然而,setInterval的代码则老是每10ms的时候尝试执行回调,不管上一次回调何时执行的。
重述下学到的知识。
JavaScript引擎只有一个线程,这使得异步事件必须排入队列等待执行
setTimeout和setInterval在执行异步代码上有着本质的区别
若是timer在将要执行的时候被阻塞,它将等待下一个时机
若是interval执行的时候很长(比指定的时间长),那么它们将连续地执行而没有延时。
原文:jQuery之父John Resig的Blog