其实,大家都知道Javascript的语言执行环境是单线程的,浏览器无论在什么时候都有且只有一个线程在运行Javascript程序。那Ajax发送异步请求怎么解释,setTimeout/setInterval定时执行回调函数又是怎么解释呢?

要说解释清楚这些问题,还得从浏览器内核处理定时器(setTimeout、setInterval)和响应浏览器事件说起。

浏览器内核允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步。浏览器内核的实现至少有三个常驻线程:javascript引擎线程、GUI渲染线程、浏览器事件触发线程。除些以外,也有一些执行完就终止的线程:如Http请求线程等,这些异步线程都会产生不同的异步事件。

我们可以通过下面这张图来理解JavaScript引擎与另外那些线程之间的通信机制。

      从图中可以看出,Javascript引擎线程是基于时间驱动的(event-driven),有一个执行队列,由回调函数(event-handler)组成,每当产生一个回调函数都会放入到Javascipt任务队列中去等待被执行。只有前面的回调函数执行完毕,才会执行后面的回调函数,如果前面的回调函数执行时被阻塞,将会导致之后的回调函数无法被执行。这些回调函数可以源自 JavaScript引擎当前执行的代码块,如调用setTimeout/setInterval,也可来是界面元素鼠标点击事件,定时触发 器时间到达通知,异步请求状态变更通知等。
 
      我们可以写一段代码验证上面说法。
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8" >
<title>测试</title>
<style>
*{margin:0;padding:0}
body{background-color:#000000; color: #ffffff}
</style>
</head> <body>
<script type="text/javascript">
setTimeout(function(){
while(true){
console.log("Do first CallBack");
}
},1000);
setInterval(function(){
console.log("Do second CallBack_____"+new Date().getTime());
},2000);
</script>
</body>
</html>

执行结果告诉我们,setInterval的回调函数一直没有被执行,在执行setTimeout回调函数是发生阻塞,导致执行队列后面的回调函数无法执行。

假如代码的调用方式是 setTimeout(func, 100),那么该代码被执行 100 毫秒之后,定时器的事件被触发。如果这个时候 JavaScript 引擎没有正在执行的其它代码,则与此定时器对应的 JavaScript 方法 func就可以被执行。否则的话,该 JavaScript 方法的执行就被加入到等待的队列中。当 JavaScript 引擎空闲的时候,会从这个队列中选择一个等待的 JavaScript 方法来执行。也就是说,虽然在调用 setTimeout()的时候设置的间隔时间是 100 毫秒,与之对应的 JavaScript 方法实际被执行的间隔有可能大于设定的 100 毫秒,取决于是否有其它代码正在被执行和执行所花费的时间。因此 setTimeout()的实际生效的间隔时间可能大于设定的时间。

而 setInterval()的执行方式与 setTimeout()有很大不同。假如代码的调用方式是 setInterval(func, 100),则每隔 100 毫秒,定时器的事件就会被触发。与 setTimeout()相同的是,如果当前 JavaScript 引擎空闲的话,则定时器对应的方法 func会被立即执行。否则的话,该 JavaScript 方法的执行就会被加入到等待队列中。由于定时器的事件是每隔 100 毫秒就触发一次,有可能某一次事件触发的时候,上一次事件的处理方法还没有机会得到执行,仍然在等待队列中。这个时候,这个新的定时器事件就被丢弃。需要注意的是,由于 JavaScript 引擎的这种执行方式,有可能定时器事件处理方法的两次被执行的实际时间间隔小于设定的间隔。比如上一个定时器事件的处理方法触发之后,等待了 50 毫秒才获得被执行的机会。而第二个定时器事件的处理方法被触发之后,马上就被执行了。那么这两者之间的时间间隔实际上只有 50 毫秒。因此,setInterval()并不适合实现精确的按固定间隔的调度操作。

总的来说,使用 setTimeout()和 setInterval()的时候,都不能满足精确的时间间隔。通过 setTimeout()设置的 JavaScript 方法的实际执行间隔时间不小于设定的时间,而通过 setInterval()设置的重复执行的 JavaScript 方法的间隔可能会小于设定的时间。

       那Ajax的异步请求又怎么解释呢?ajax请求是由浏览器新开一个线程来进行请求,它是把当请求的状态变更时,如果先前已设置回调,那么这回调函数将被放到 JavaScript引擎的处理队列中等待处理,这就看起来好像是javascript在进行异步多线程处理,其实不是的。

推荐一篇博客:How Javascript Timers Work.

谈谈Javascript线程的更多相关文章

  1. setTimeout setInterval 区别 javascript线程解释

    原文:http://www.iamued.com/qianduan/1645.html 今天看到这篇文章,学到了不少东西 特此发出来 和大家分享 JavaScript的setTimeout与setIn ...

  2. javascript线程解释(setTimeout,setInterval你不知道的事)---转载

    在工作中,可能我们经常遇到在有很多 setInterval 的页面, 再手动触发 setTimeout 的时候经常失败, 尤其是 jquery做动画的时候,一些渐入溅出的东西,很多东西都不被触发……, ...

  3. 再看JavaScript线程

    继上篇讨论了一些关于JavaScript线程的知识,我们不妨回过头再看看,是不是JavaScript就不能多线程呢?看下面一段很简单的代码(演示用,没考虑兼容问题): 代码判断一: <div i ...

  4. javascript线程解释(setTimeout,setInterval你不知道的事)

    john resig写的一篇文章: 原文地址:http://ejohn.org/blog/how-javascript-timers-work/ 作为入门者来说,了解JavaScript中timer的 ...

  5. 谈谈javaScript

    谈谈javaScript  (杰我学习) 一. 什么是JavaScript       人们通常所说的JavaScript,其正式名称为ECMAScript.这个标准由ECMA组织发展和维护.ECMA ...

  6. 《windows核心编程系列》十五谈谈windows线程栈

    谈谈windows线程栈. 当系统创建线程时会为线程预订一块地址空间区域,注意仅仅是预订.默认情况下预定的这块区域的大小是1MB,虽然预订这么多,但是系统并不会给全部区域调拨物理存储器.默认情况下,仅 ...

  7. JavaScript线程

    JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如 setTimeout( ...

  8. 谈谈javascript中的prototype与继承

    谈谈javascript中的prototype与继承 今天想谈谈javascript中的prototype. 通常来说,javascript中的对象就是一个指向prototype的指针和一个自身的属性 ...

  9. Java:谈谈控制线程的几种办法

    目录 Java:谈谈控制线程的几种办法 join() sleep() 守护线程 主要方法 需要注意 优先级 弃用三兄弟 stop() resume suspend 中断三兄弟 interrupt() ...

随机推荐

  1. Linux伙伴系统1

    (一)--伙伴系统的概述 Linux内核内存管理的一项重要工作就是如何在频繁申请释放内存的情况下,避免碎片的产生.Linux采用伙伴系统解决外部碎片的问题,采用slab解决内部碎片的问题,在这里我们先 ...

  2. Objective-c Category(类别)

    NSStringUtilities.h: #import <Foundation/Foundation.h> @interface NSString(Utilities) -(BOOL) ...

  3. 【HDOJ】1258 Sum It Up

    典型的深搜,剪枝的时候需要跳过曾经搜索过的相同的数目,既满足nums[i]=nums[i-1]&&visit[i-1]==0,visit[i-1]==0可以说明该点已经测试过. #in ...

  4. BOM List demo

    select level level_id,        t.*   from (select msi1.segment1 farther_item,                msi1.inv ...

  5. Android开发之PendingIntent的使用

    PendingIntent,待确定的意图,等待的意图 官网链接:http://developer.android.com/reference/android/app/PendingIntent.htm ...

  6. CSS属性一览

    CSS 属性 CSS 属性组: 动画 背景 边框和轮廓 盒(框) 颜色 内容分页媒体 定位 可伸缩框 字体 生成内容 网格 超链接 行框 列表 外边距 Marquee 多列 内边距 分页媒体 定位 打 ...

  7. DesignPatterns

    1.设计模式,说明工厂模式.  总共23种,分为三大类:创建型,结构型,行为型 创建型 1. Factory Method(工厂方法) 2. Abstract Factory(抽象工厂) 3. Bui ...

  8. [HDU POJ] 逆序数

    HDU 1394 Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/3276 ...

  9. 从头开始编写一个Orchard网上商店模块(2) - 配置您的Orchard开发环境

    原文地址:http://skywalkersoftwaredevelopment.net/blog/writing-an-orchard-webshop-module-from-scratch-par ...

  10. Oracle 新增表空间文件

    ALTER TABLESPACE users ADD DATAFILE 'D:/oracle/oradata/orcl/users.dbf' SIZE 500M AUTOEXTEND ON NEXT ...