`

(ZZ)JavaScript的单线程性质以及定时器的工作原理

 
阅读更多

How JavaScript Timers Work

 

从基础的层面来讲,理解JavaScript的定时器是如何工作的是非常重要的。计时器的执行常常和我们的直观想象不同,那是因为JavaScript引擎是单线程的。我们先来认识一下下面三个函数是如何控制计时器的。

  • var id = setTimeout(fn, delay); - 初始化一个计时器,然后在指定的时间间隔后执行。该函数返回一个唯一的标志ID(Number类型),我们可以使用它来取消计时器。
  • var id = setInterval(fn, delay); - 和setTimeout有些类似,但它是连续调用一个函数(时间间隔是delay参数)直到它被取消。
  • clearInterval(id);clearTimeout(id); - 使用计时器ID(setTimeout 和 setInterval的返回值)来取消计时器回调的发生

为了理解计时器的内在执行原理,有一个重要的概念需要加以探讨:计时器的延迟(delay)是无法得到保障的。由于所有JavaScript代码是在一个线程里执行的,所有异步事件(例如,鼠标点击和计时器)只有拥有执行机会时才会执行。用一个很好的图表加以说明:

 


(点击查看大图)

 

在这个图表中有许多信息需要理解,如果完全理解了它们,你会对JavaScript引擎如何实现异步事件有一个很好的认识。这是一个一维的图标:垂直方向表示时间,蓝色的区块表示JavaScript代码执行块。例如第一个JavaScript代码执行块需要大约18ms,鼠标点击所触发的代码执行块需要11ms,等等。

由于JavaScript引擎同一时间只执行一条代码(这是由于JavaScript单线程的性质),所以每一个JavaScript代码执行块会“阻塞”其它异步事件的执行。这就意味着当一个异步事件发生(例如,鼠标点击,计时器被触发,或者Ajax异步请求)后,这些事件的回调函数将排在执行队列的最后等待执行(实际上,排队的方式根据浏览器的不同而不同,所以这里只是一个简化);

从第一个JavaScript执行块开始研究,在第一个执行块中两个计时器被初始化:一个10ms的setTimeout()和一个10ms的setInterval()。依据何时何地计时器被初始化(计时器初始化完毕后就会开始计时),计时器实际上会在第一个代码块执行完毕前被触发。但是,计时器上绑定的函数不会立即执行(不被立即执行的原因是JavaScript是单线程的)。实际上,被延迟的函数将依次排在执行队列的最后,等待下一次恰当的时间再执行。

此外,在第一个JavaScript执行块中我们看到了一个“鼠标点击”事件发生了。一个JavaScript回调函数绑定在这个异步事件上了(我们从来不知道用户什么时候执行这个(点击)事件,因此认为它是异步的),这个函数不会被立即执行,和上面的计时器一样,它将排在执行队列的最后,等待下一次恰当的时候执行。

当第一个JavaScript执行块执行完毕后,浏览器会立即问一个问题:哪个函数(语句)在等待被执行?在这时,一个“鼠标点击事件处理函数”和一个“计时器回调函数”都在等待执行。浏览器会选择一个(实际上选择了“鼠标点击事件的处理函数”,因为由图可知它是先进队的)立即执行。而“计时器回调函数”将等待下次适合的时间执行。

注意,当“鼠标点击事件处理函数”执行的时候,setInterval的回调函数第一次被触发了。和setTimeout的回调函数一样,它将排到执行队列的最后等待执行。但是,一定要注意这一点:当setInterval回调函数第二次被触发时(此时setTimeout函数仍在执行)setTimeout的第一次触发将被抛弃掉。当一个很长的代码块在执行时,可能把所有的setInterval回调函数都排在执行队列的后面,代码块执行完之后,结果便会是一大串的setInterval回调函数等待执行,并且这些函数之间没有间隔,直到全部完成。所以,浏览器倾向于的当没有更多interval的处理函数在排队时再将下一个处理函数排到队尾(这是由于间隔的问题)。

我们能够发现,当第三个setInterval回调函数被触发时,之前的setInterval回调函数仍在执行。这就说明了一个很重要的事实:setInterval不会考虑当前正在执行什么,而把所有的堵塞的函数排到队列尾部。这意味着两次setInterval回调函数之间的时间间隔会被牺牲掉(缩减)。

最后,当第二个setInterval回调函数执行完毕后,我们可以看到没有任何程序等待JavaScript引擎执行了。这就意味着浏览器现在在等待一个新的异步事件的发生。在50ms时一个新的setInterval回调函数再次被触发,这时,没有任何的执行块阻塞它的执行了。所以它会立刻被执行。

让我们用一个例子来阐明setTimeoutsetInterval之间的区别:

  setTimeout(function(){
    /* Some long block of code... */
    setTimeout(arguments.callee10);
  }10);
  
  setInterval(function(){
    /* Some long block of code... */
  }10);
 

这两句代码乍一看没什么差别,但是它们是不同的。setTimeout回调函数的执行和上一次执行之间的间隔至少有10ms(可能会更多,但不会少于10ms),而setInterval的回调函数将尝试每隔10ms执行一次,不论上次是否执行完毕。

在这里我们学到了很多知识,总结一下:

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

上述这些知识点都是非常重要的。了解了JavaScript引擎是如何工作的,尤其是大量的异步事件(连续)发生时,才能为构建高级应用程序打好基础。

 

 

原文链接 http://www.phpweblog.net/rainman/archive/2009/01/05/6267.html

分享到:
评论

相关推荐

    base zz zz zz zz

    base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz

    ZzJavaScript encode and escape functions

    JavaScript中的编码和转义函数主要有encodeURI、encodeURIComponent和escape这三个函数,它们用于处理URL和URI中的特殊字符。下面将详细介绍这三个函数的功能和使用场景。 首先,encodeURI函数的主要用途是编码整个...

    现代通信原理考试试题zz

    现代通信原理考试试题zz现代通信原理考试试题zz

    5152单片机proteus仿真和源码用定时器T0的中断实现长时间定时

    在本篇文章中,我们将深入探讨如何利用5152单片机与Proteus软件结合,在定时器T0中断的基础上实现长时间定时的功能。...这不仅有助于加深对单片机定时器工作原理的理解,也为进一步探索其他高级功能奠定了坚实的基础。

    5152单片机proteus仿真和源码发一个用定时器做的PWM

    #### 定时器工作原理 在单片机中,定时器主要用于产生周期性的中断或者测量时间间隔。通过配置定时器的预分频器、比较寄存器等参数,可以精确地控制定时器的溢出时间,进而实现不同频率和占空比的PWM波形输出。 ###...

    CString的工作原理介绍(zz).docx

    《深入理解CString的工作原理》 cstring,作为Microsoft MFC库中的重要成员,是C++对标准C字符串的封装,旨在解决C语言中字符串处理带来的诸多问题,如缓冲溢出和内存泄漏。这篇文章将深入探讨CString的工作原理,...

    8051Proteus仿真c源码定时器控制数码动态显示

    综上所述,“8051 Proteus 仿真 C 源码定时器控制数码动态显示”这一知识点涵盖了 8051 微控制器的基础知识、Proteus 仿真的使用方法、C 语言编程技巧、定时器的工作原理以及数码动态显示技术的应用等多个方面。...

    5152单片机proteus仿真和源码用定时器T1查询方式控制单片机发出1KHz音频

    根据给定文件的信息,我们可以提炼出以下几个核心知识点:5152单片机的基本概念、Proteus软件的使用、定时器T1的工作原理及应用、查询方式在定时器中的运用以及如何通过单片机发出1KHz音频信号。 ### 一、5152...

    ZZ: 时间管理方法(转贴)

    2. **番茄工作法**:这种方法使用定时器将工作划分为25分钟的工作块,每个工作块后休息5分钟,四个工作块后长休15分钟。这种分割工作和休息的方式有助于保持专注并防止疲劳。 3. **敏捷开发中的时间管理**:敏捷...

    5152单片机proteus仿真和源码用定时器设计的门铃

    这不仅包括了如何利用5152单片机及其仿真软件Proteus来实现一个简单的门铃系统,还包括了具体的编程和调试方法,以及如何通过定时器来控制门铃的响铃时间和间隔。 ### 一、5152单片机简介 5152单片机实际上是指...

    8051Proteus仿真c源码定时器控制数码管动管显示

    8051内置有两个16位的定时器/计数器,即T0和T1,每个定时器都具有多种工作模式,可以通过设置相关的寄存器来配置。定时器的工作模式包括: - **模式0**:13位定时器/计数器。 - **模式1**:16位定时器/计数器。 - **...

    5152单片机proteus仿真和源码用定时器T0的中断实现渴望主题曲的播放

    1. **设置定时器工作模式**:通常选择模式1或模式2,根据不同的需求选择合适的工作模式。 2. **初始化定时器初值**:根据所选模式计算出合适的初始值,以达到所需的定时时间。 3. **使能中断**:打开定时器中断,并...

    8051Proteus仿真c源码按键控制定时器选播多段音乐

    2. **定时器配置**:设置定时器的工作模式、预置值等参数,以满足音乐播放所需的定时精度。 3. **音乐数据存储**:将音乐数据以适当格式存储在程序存储器中。 4. **播放逻辑**:根据当前状态(如按键输入、定时器...

    5152单片机proteus仿真和源码用定时器T0查询方式P2口8位控制LED闪烁

    Proteus是一款强大的电路设计与仿真软件,能够支持电路原理图的设计、PCB板的设计以及单片机程序的调试等功能。它主要由两部分组成: 1. **ISIS**:用于绘制电路原理图。 2. **ARES**:用于PCB设计布局。 Proteus...

    ZZ561401.CAB

    ZZ561401.CAB ZZ561401.CAB ZZ561401.CAB

    zz809.com留言本

    《zz809.com留言本》是一款基于网络的互动交流平台,源于柏图留言本BTB 1.2版本,并经过管理员zz809的定制和优化。...通过下载和研究这个源码,我们可以深入理解网络留言系统的构建原理,提升自己的编程能力。

    atmega16开发板电路原理图

    ATmega16拥有16KB的系统内可编程Flash、512字节的EEPROM、1KB的SRAM、32个通用I/O口线、32个通用工作寄存器、四个灵活的定时器/计数器、两个串行 USART、一个可编程的串行接口、一个具有比较模式的16位定时器、片上...

    5152单片机proteus仿真和源码用定时器T1中断控制两个LED以不同周期闪烁

    此项目不仅能够帮助初学者更好地理解单片机的工作原理,还能够提升他们在实际应用中的编程技巧。 #### 一、项目背景及意义 随着科技的发展,单片机已经成为自动化领域不可或缺的一部分。5152单片机作为一种经典的8...

    8051Proteus仿真c源码定时器控制交通指示灯

    8051 微控制器的核心包括一个 CPU、RAM、ROM(或闪存)、定时器/计数器、串行通信接口以及 I/O 口等。 #### 知识点二:Proteus 仿真软件概述 Proteus 是一种用于电路设计和仿真的软件工具。该软件由 Labcenter ...

    wincc AX NF ZZ

    wincc SIMATIC WinCC是第一个使用最新的32位技术的过程监视系统,具有良好的开放性和灵活性。 从面市伊始,用户就对SIMATIC WinCC印象深刻。

Global site tag (gtag.js) - Google Analytics