从根本上讲,了解JavaScript计时器的工作方式很重要。
通常,他们的行为是非直觉的,因为他们在的单线程。让我们开始检查我们有权访问,可以构造和操纵计时器的三个函数。
var id = setTimeout(fn, delay);
- 启动单个定时器,在延迟后调用指定的功能。
该函数返回一个唯一的ID,以后可以取消定时器。
var id = setInterval(fn, delay);
- 类似于
setTimeout
但不断地调用函数(每次都有延迟),直到它被取消。
clearInterval(id);
,
clearTimeout(id);
- 接受计时器ID(由上述任一函数返回),并停止计时器回调发生。
为了了解定时器如何在内部工作,有一个重要的概念,需要探讨:定时器延迟不能保证。
由于浏览器中的所有JavaScript都在单个线程上执行,因此异步事件(例如鼠标点击和计时器)只在执行过程中出现打开时运行。
这是最好的图表,如下所示:
在这个图中有很多信息来消化,但是完全理解它会让你更好地实现异步JavaScript执行的工作原理。
这个图是一维的:垂直的,我们有(挂钟)时间,以毫秒为单位。
蓝色框表示正在执行的JavaScript的部分。
例如,第一个JavaScript块执行大约18ms,鼠标点击块大约11ms,依此类推。
由于JavaScript只能一次执行一段代码(由于它的单线程性质),这些代码块中的每一个都“阻塞”其他异步事件的进度。
这意味着当异步事件发生时(如鼠标点击,定时器触发或XMLHttpRequest完成),它会排队等待稍后执行(如何实际发生这种排队,从浏览器到浏览器确实有所不同,因此,简化)。
首先,在第一个JavaScript块中,启动两个定时器:10ms
setTimeout
和10ms
setInterval
。
由于定时器启动的地点和时间,它实际上是在我们实际完成第一个代码块之前触发的。
但是,请注意,它不会立即执行(它不能这样做,因为线程)。
相反,延迟功能被排队以便在下一可用时刻执行。
此外,在第一个JavaScript块中,我们看到鼠标点击发生。
与该异步事件相关联的JavaScript回调(我们从不知道用户何时可以执行动作,因此认为它是异步的)不能立即执行,因此,像初始定时器一样,它被排队等待稍后执行。
在JavaScript完成执行浏览器的初始块之后立即提出问题:什么是等待执行?
在这种情况下,鼠标点击处理程序和计时器回调都在等待。
浏览器然后选择一个(鼠标单击回调)并立即执行它。
定时器将等待下一个可能的时间,以便执行。
注意,当鼠标点击处理程序正在执行第一个间隔回调时执行。
与定时器一样,其处理程序排队等待以后执行。
但是,请注意,当间隔被再次触发时(当定时器处理程序正在执行时),这次将删除处理程序执行。
如果要在大块代码执行时将所有间隔回调排队,那么结果将是一堆执行的间隔,在它们之间没有延迟,完成后。
相反,浏览器往往只是等待,直到没有更多的间隔处理程序排队(在有问题的时间间隔),然后排队更多。
事实上,我们可以看到,当第三个间隔回调触发,而间隔本身正在执行时,就是这种情况。
这显示了一个重要的事实:间隔不关心当前正在执行什么,它们将不加区别地排队,即使它意味着回调之间的时间将被牺牲。
最后,在第二个间隔回调完成执行后,我们可以看到没有什么要留给JavaScript引擎执行。
这意味着浏览器现在等待一个新的异步事件发生。
我们得到这个在50ms标记时间间隔再次发生。
这一次,但是,没有阻塞其执行,所以它立即激发。
让我们看一个例子,以更好地说明之间的差异
setTimeout
和
setInterval
。
setTimeout(function(){
/ * Some long block of code ... * /
setTimeout(arguments.callee,10);
},10);
setInterval(function(){
/ * Some long block of code ... * /
},10);
这两段代码看起来在功能上等同,乍一看,但他们不是。
值得注意的是,
setTimeout
代码将在上一个回调执行之后至少有10ms的延迟(它可能会更多,但从不会少),而
setInterval
不管何时执行最后一个回调,将每10ms尝试执行一个回调。
我们在这里学到了很多,让我们回顾一下:
JavaScript引擎只有一个线程,强制异步事件队列等待执行。
setTimeout
并且
setInterval
在它们如何执行异步代码方面根本不同。
如果定时器被阻止立即执行,它将被延迟,直到下一个可能的执行点(这将长于所需的延迟)。
如果间隔可以执行(长于指定的延迟)时间,则可以无延迟地执行背对背。
所有这些都是非常重要的知识。
了解JavaScript引擎的工作原理,尤其是通常发生的大量异步事件,为构建高级应用程序代码提供了一个良好的基础。