其实,大家都知道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. Android 三档自定义滑动开关,禁止点击功能的实现,用默认的seekbar组件实现

    android三档自定义滑动开关,禁止点击功能的实现,普通开关网上有很多例子,三档滑动开关的则找了整天都没有相关例子,开始用普通开关的源码修改了自己实现了一个类,但效果不如人意,各种边界情况的算法很难 ...

  2. Sass占位符选择器`%`

    摘录自Understanding placeholder selectors. @extend @extend让你能够在多个选择器中通过继承的方式共享一段样式: .icon { transition: ...

  3. web storm使用和配置

    官网:http://www.jetbrains.com/webstorm/ webStorm,File=>setting=>JavaScript-Libraries How WebStor ...

  4. java代码转换为c# 工具

    Demo Java to C# Converter.exe 已下载到 F:\SoftWare-new\java\Java_to_CSharp_Converter.rar

  5. c#浅谈反射内存的处理

    这段时间由于公司的项目的要求,我利用c#的反射的机制做了一个客户端框架.客户端里的所有的模块都是以一定形式进行提供,例如:FORM,UserControl. 在做的过程中很简单与愉快.具体的过程如下: ...

  6. iOS 开发者计划申请 2014 年最新心得[转]

    iOS 开发者计划申请 2014 年最新心得 http://myfairland.net/ios-developer-program/

  7. SharePoint Site Pages & Application Pages

    转:http://www.wcode.net/plus/view.php?aid=1582071 SharePoint一个很重要的概念就是Site Pages和Application Pages.接触 ...

  8. android webview 访问https页面 SslError 处理

    在Android中,WebView可以用来加载http和https网页到本地应用的控件.但是在默认情况下,通过loadUrl(String url)方法,可以顺利loadUrl(“http://www ...

  9. SSO单点登录解决方案[转载]

    1 什么是单点登陆      单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互 ...

  10. 如何监听非本地IP

    做HA的时候,如果每个机器上同时需要监听多个IP的同一个端口.那么肯定是需要写死监听的IP和端口.比如在haproxy里面: frontend free bind default_backend te ...