How JavaScript Timers Work
Posted Rank-Bill
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了How JavaScript Timers Work相关的知识,希望对你有一定的参考价值。
本文翻译自https://johnresig.com/blog/how-javascript-timers-work/ 版权归作者所有,仅供学习与参考使用。有些知识时间长了忘记了,建议自己记录下来。
前一篇文章讲诉了microtask与macrotask,结合这篇文章会对JS的执行理解更为透彻!
从根本上讲,理解JavaScript计时器的工作原理非常重要。通常情况下,它们的行为是不直观的,因为它们是单线程。让我们从可以构造和操作计时器的三个函数开始。
- var id = setTimeout(fn,delay) ; 初始化一个定时器并在指定的时间内调用回调函数。该函数会返回一个唯一的定时器 ID,我们剋在之后通过此ID 清除这个定时器
- var id = setInterval(fn,delay);和setTimeout类似,但是会在每一个延时后持续的调用fn,直至这个定时器被清除
- clearInterval(id);clearTimeout(id); 传入的参数是定时器ID,并会停止计时器的回调(非直接中断函数)
为了更进一步的理解计时器内部是如何工作的,有一个重要的概念需要认识:计时器延迟并不可靠(timer delay is not guaranteed)。由于浏览器中的所有JavaScript单线程执行的,因此异步事件(如鼠标单击和计时器)在有空闲时执行。用图表最好地说明了这一点,如下所示:
图中有很多信息需要领会,但是完全理解它将使您更好地了解JavaScript异步执行流程。这个图是线性的:垂直方向表示时间,以毫秒为单位。蓝色框表示正在执行的JavaScript部分。例如,第一个JavaScript块大约执行18ms,鼠标单击块大约执行11ms,等。
由于JavaScript一次只能执行一段代码(由于它的单线程性质),这些代码块中会“阻塞”了其他异步事件的进程。这意味着当异步事件发生时(如鼠标单击、计时器触发或XMLHttpRequest完成)时,它将排队等待稍后执行(各浏览器对排队实现可能各有差异)。
首先,在第一个JavaScript块中,会启动两个计时器:10ms setTimeout和10ms setInterval。无论计时器是在何时何地启动的,都会在完成第一个代码块之前被触发(JavaScript)。但是,它不会立即执行(由于单线程,它无法执行)。取而代之,延迟函数将会被排队,以便在下一个可用时刻执行(task)。
除此之外,在第一个JavaScript块中,有mouse click点击事件。与此异步事件关联的JavaScript回调(我们永远不知道用户什么时候会执行某个操作,因此认为它是异步的)无法立即执行,因此,与初始计时器一样,让它排队等待稍后执行。
在JavaScript的初始块完成执行后,浏览器立即会问这样一个问题:等待执行的是什么(what waiting)?在这种情况下,鼠标单击处理程序和计时器回调都在等待。然后浏览器选择(鼠标单击回调)并立即执行它。计时器将等待到下一个可能的时间,以便执行。
注意,虽然鼠标单击处理程序正在执行第一个interval回调执行。与计时器一样,它的处理程序排队等待稍后执行。但是,当interval再次触发时(当计时器处理程序执行时),此处理程序执行将被删除。如果您要在执行大量代码时对所有Interval回调进行排队,那么在完成时,结果将是一系列Interval执行,它们之间没有延迟。相反,浏览器倾向等到没有更多的Intereval处理程序排队。
实际上,我们可以看到,当第三个Interval回调触发时,这个Interval本身正在执行。这向我们展示了一个重要的事实:Interval不在乎当前正在执行什么,它们将不分青红皂白地排队,即使这意味着回调之间的时间将被牺牲。
最后,在执行完第二个interval回调之后,我们可以看到JavaScript引擎已经没有什么可执行的了。这意味着浏览器现在等待一个新的异步事件发生。当Interval再次触发时,我们在50ms标记处得到这个。然而,这一次,没有任何东西阻止它的执行,因此它立即触发。
让我们看一个例子来更好地说明setTimeout和setInterval之间的区别。
setTimeout(函数()
/*一些长的代码块…* /
setTimeout(arguments.callee,10);
,10);
setInterval(函数()
/*一些长的代码块…* /
,10);
乍一看,这两段代码在功能上可能是相同的,但实际上并非如此。值得注意的是,setTimeout代码在前一次回调执行之后总是会有至少10ms的延迟(它可能最终会更多,但绝不会更少),而setInterval会尝试每10ms执行一次回调,而不管上一次回调是什么时候执行的。
我们在这里学到了很多,让我们来回顾一下:
- JavaScript引擎是单线程,迫使异步事件排队等待执行
- setTimeout和setInterval在执行异步代码的方式上是完全不同的。
- 如果一个计时器被阻止立即执行,它将被延迟到下一个可能的执行点(比预期的延迟要长)。
- 如果执行的时间足够长(超过指定的延迟),Interval可以连续执行,而不会延迟。
以上是关于How JavaScript Timers Work的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript jFlow AutoTimer(以及JavaScript和jQuery事件中的Timers示例)
How to search for a part of a word with ElasticSearch.md