JavaScript到底是不是单线程
JavaScript到底是不是单线程
JavaScript引擎
在了解计时器内部运作前,我们必须清楚一点,触发和执行并不是同一概念,计时器的回调函数一定会在指定delay的时间后被触发,但并不一定立即执行,可能需要等待。所有JavaScript代码是在一个线程里执行的,像鼠标点击和计时器之类的事件只有在JS单线程空闲时才执行。
我们来看一下图表,一开始你可能并没发现什么或啥都不懂,但请静下心来,在脑海里绘制出这个场景

这个图表中有许多数据信息等着我们去理解,当你完全理解了这个图,你会对js的异步运行机制(即JavaScript引擎如何实现异步事件)有很好的了解。这个图是一维的,垂直线上是以毫秒计位,蓝色块代表被划分的不同的js区域执行代码。例如,第一个JS区块执行了18毫秒,鼠标点击事件被阻塞了将近11毫秒,等等。
由于JavaScript引擎同一时间只执行一段代码(这是由JavaScript单线程的性质决定的),所以每个JS代码块阻塞了其它异步事件的进行。这意味着当一个异步事件(像鼠标点击、计时器、Ajax)发生时,这些事件的回调函数将排在队列后面等待执行(如何排队完全取决于各浏览器,而我们可以忽视它们内部差异,作一个简化处理)。
我们首先从第一个JS代码块开始,有两个计时器被初始化:一个10ms的setTimeout和一个10ms的setInterval.观察计时器初始化位置,(计时器初始化完毕后就会开始计时),发现setTimeout计时器的回调实际上会在第一个代码块执行完毕前被触发。但是这里注意的是,它不会立即执行(单线程不能这样做)。实际上,触发的回调将被排成一个队列,等待下一个可执行时间。
此外,在第一个JS代码块,我们发现一个鼠标点击事件被触发。这个鼠标点击JS回调被绑定在异步队列上(我们从来不知道用户什么时候执行这个操作,所以它被认为是异步的)且不能马上执行。像初始化的计时器一样,排队等待执行。
执行完初始化JS代码块后,浏览器就有个疑问:谁在等待执行?此时,鼠标点击回调和setTimeout计时器的回调都在等待。浏览器将选一个(鼠标点击事件)并立马执行。而计时器的回调将等待下一合适时机执行。
注意,鼠标点击事件执行过程中,interval的回调第一次被触发,与setTimeout的回调一样,排队等待执行。随着时间推移,等到setTimeout计时器的回调执行时候,setInterval的回调再次被触发,这次被触发的回调将被抛弃。如果一大段代码块正在执行,所有的setInterval的回调都将要排队,一旦大段代码块执行完毕,这些一连串的setInterval的回调相互间将被无延迟地执行。实际上,浏览器处理setInterval被触发的回调排队等待执行时,除非队列中setInterval回调为空,才允许新的setInterval的回调加入。
我们发现,setInterval的第一个被触发的回调执行时,setInterval的回调又被触发且排到队列。这向我们传达一个重要的消息:setInterval不关心目前JS正在执行的内容,setInterval的被触发的回调都将会无差别地排队。
最后,当setInterval的回调执行两次后,我们发现没有javascript引擎要执行东西。这意味着浏览器将等待着一个新的异步事件发生。我们知道,在50ms时候,setInterval的回调再次被触发,但这次并没有东西阻塞,所以回调就立马执行了。
在浏览器中,JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,这些任务可能源自当前执行的代码块,如调用setTimeout(),也可能来自浏览器内核,如onload()、onclick()、onmouseover()、setTimeOut()、setInterval()、Ajax等。如果从代码的角度来看,所谓的任务实体就是各种回调函数,由于“单线程”的原因,这些任务会进行排队,一个接着一个等待着被引擎处理。(这段说法来源于http://www.benben.cc/blog/?p=327)
JavaScript引擎线程和其它侦听线程

上图中,定时器和事件都按时触发了,这表明JavaScript引擎的线程和计时器触发线程、事件触发线程是三个单独的线程,即使JavaScript引擎的线程被阻塞,其它两个触发线程都在运行。
浏览器内核实现允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步。假如某一浏览器内核的实现至少有三个常驻线程: JavaScript引擎线程,事件触发线程,Http请求线程,下面通过一个图来阐明单线程的JavaScript引擎与另外那些线程是怎样互动通信的。虽然每个浏览器内核实现细节不同,但这其中的调用原理都是大同小异。
线程间通信:JavaScript引擎执行当前的代码块,其它诸如setTimeout给JS引擎添加一个任务,也可来自浏览器内核的其它线程,如界面元素鼠标点击事件,定时触发器时间到达通知,异步请求状态变更通知等.从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线程关系,这些任务得进行排队,一个接着一个被引擎处理.
GUI渲染也是在引擎线程中执行的,脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出来,这些操作将保存在一个队列中,待JavaScript引擎空闲时才有机会渲染出来。来看例子(这块内容还有待验证,个人觉得当Dom渲染时,才可阻止渲染)
<div id="test">test</div>
<script type="text/javascript" language="javascript">
var i=0;
while(1) {
document.getElementById("test").innerHTML+=i++ + "<br />";
}
</script>
这段代码的本意是从0开始顺序显示数字,它们将一个接一个出现,现在我们来仔细研究一下代码,while(1)创建了一个无休止的循环,但是对于单线程的JavaScript引擎而言,在实际情况中就会造成浏览器暂停响应并处于假死状态。
alert()会停止JS引擎的执行,直到按确认键,在JS调试的时候,查看当前实时页面的内容。
Ajax时如何实现异步的
很多同学朋友搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求(参见上图),当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行onreadystatechange所设置的函数。
原文链接: http://www.cnblogs.com/sprying/archive/2013/05/26/3100639.html
JavaScript到底是不是单线程的更多相关文章
- Javascript定时器(一)——单线程
一.JavaScript 引擎是单线程的 可以从下面的代码中看到,第一个用setTimeout中的代码是死循环,由于是单线程,下面的两个定时器就没机会执行了. <script type=&quo ...
- JavaScript之JS单线程|事件循环|事件队列|执行栈
本博文基于知乎"JavaScript作用域问题?"一问,而引起了对JavaScript事件循环和单线程等概念与实践上的研究.深入理解. 一.概念 0.关键词:JavaScript单 ...
- JavaScript引擎是单线程的
从基础的层面来讲,理解JavaScript的定时器是如何工作的是非常重要的.计时器的执行常常和我们的直观想象不同,那是因为JavaScript引擎是单线程的.我们先来认识一下下面三个函数是如何控制计时 ...
- Javascript:必须知道的Javascript知识点之“单线程事件驱动”
heiboard: Javascript:必须知道的Javascript知识点之“单线程事件驱动”
- web前端分享JavaScript到底是什么?特点有哪些?
web前端分享JavaScript到底是什么?特点有哪些?这也是成为web前端工程师必学的内容.今天为大家分享了这篇关于JavaScript的文章,我们一起来看看. 一.JavaScript是什么? ...
- Javascript引擎的单线程机制和setTimeout执行原理阐述
工作中使用setTimeout解决了一个问题,于是对setTimeout的相关资料整理了下,以及对js引擎执行的原理一并整理了下,希望能给码农们一些帮助.若发现有错的地方大家及时指出,共同学习进步. ...
- 对Javascript到底了解多少,一测便知道
笔者在这里附上一段代码,请读者思考一下程序的运行结果: console.log(a); //??? a(); var a=3; function a(){ console.log(10); } con ...
- JavaScript异步和单线程
一,同步和异步的区别: 同步会阻塞代码执行,而异步不会.(比如alert是同步,setTimeout是异步) 二,前端使用异步的场景: 1,定时任务:setTimeout,setInterval 2, ...
- 【前端知识体系-JS相关】深入理解JavaScript异步和单线程
1. 为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Jav ...
随机推荐
- RocksDB笔记 - Compaction中的Iterator
Compaction中的Iterator 一般来说,Compaction的Input涉及两层数据的合并,对于涉及到的每一层数据: 如果是level-0,对level-0的每一个sstable文件建立一 ...
- android 中View的优化
在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候, ...
- Ubuntu下不重装系统安装SSD总结
一.要想给自己的机子装个固态,但又不想重装系统,各种配置,那么就要先把自己的系统从HDD复制到SSD上,这里说下我的情况.我的HDD 是500G ubuntu系统,安装的时候没有分区,默认是dev/s ...
- <Android>文件下载
使用HTTP协议下载文件 创建一个URL对象 通过URL对象,创建一个HttpURLConnection对象 调用getInputStream()方法得到InputStream对象 从InputStr ...
- 使用Maven自动部署Tomcat 6和Tomcat 7下Web应用
使用Maven自动部署Tomcat 6和Tomcat 7下Web应用 开启Tomcat远程管理权限 在tomcat的config目录下的tomcat-users.xml文件, <role rol ...
- toad的基本操作
1.把鼠标停在sql所在行,然后ctrl+Enter直接执行当前sql. 2.解决Toad对中文显示乱码问题(如果数据库所在主机的NLS_LANG是AMERICAN_AMERICA.WE8ISO885 ...
- IO-03. 求整数均值(10)
本题要求编写程序,计算4个整数的和与平均值.题目保证输入与输出均在整型范围内. 输入格式: 输入在一行中给出4个整数,其间以空格分隔. 输出格式: 在一行中按照格式“Sum = 和; Average ...
- LNMP 部署
一.防火墙配置 CentOS 7.x默认使用的是firewall作为防火墙,这里改为iptables防火墙. 1.关闭firewall: systemctl stop firewalld.servic ...
- Restful.Data,现招募有为骚年,群号 338570336
光阴似箭,日月如梭,套用小学作文惯用的一句开场白来开始重新开始我的博客园生涯吧. 8年的风霜雪雨,不断的击打着我内心的哀伤,可我依旧坚挺的屹立在这里,是因为技术是我一直坚持的梦想. 追寻着先辈和高人的 ...
- EQueue - 一个C#写的开源分布式消息队列的总体介绍
前言 本文想介绍一下前段时间在写enode时,顺便实现的一个分布式消息队列equeue.这个消息队列的思想不是我想出来的,而是通过学习阿里的rocketmq后,自己用c#实现了一个轻量级的简单版本.一 ...