单线程的JavaScript
推荐阅读:JavaScript 运行机制详解:再谈Event Loop
为什么JS要设计成单线程?
引用阮老师的原话:
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
Javascript是单线程的
因为JS运行在浏览器中,是单线程的,每个window一个JS线程,既然是单线程的,在某个特定的时刻只有特定的代码能够被执行,并阻塞其它的代码。而浏览器是事件驱动的(Event driven),浏览器中很多行为是异步(Asynchronized)的,会创建事件并放入执行队列中。javascript引擎是单线程处理它的任务队列,你可以理解成就是普通函数和回调函数构成的队列。当异步事件发生时,如mouse click, a timer firing, or an XMLHttpRequest completing(鼠标点击事件发生、定时器触发事件发生、XMLHttpRequest完成回调触发等),将他们放入执行队列,等待当前代码执行完成。
异步事件驱动
前面已经提到浏览器是事件驱动的(Event driven),浏览器中很多行为是异步(Asynchronized)的,例如:鼠标点击事件、窗口大小拖拉事件、定时器触发事件、XMLHttpRequest完成回调等。当一个异步事件发生的时候,它就进入事件队列。浏览器有一个内部大消息循环,Event Loop(事件循环),会轮询大的事件队列并处理事件。例如,浏览器当前正在忙于处理onclick事件,这时另外一个事件发生了(如:window onSize),这个异步事件就被放入事件队列等待处理,只有前面的处理完毕了,空闲了才会执行这个事件。setTimeout也是一样,当调用的时候,js引擎会启动定时器timer,大约xxms以后执行xxx,当定时器时间到,就把该事件放到主事件队列等待处理(浏览器不忙的时候才会真正执行)。
浏览器不是单线程的
虽然JS运行在浏览器中,是单线程的,每个window一个JS线程,但浏览器不是单线程的,例如Webkit或是Gecko引擎,都可能有如下线程:
- javascript引擎线程
- 界面渲染线程
- 浏览器事件触发线程
- Http请求线程
很多童鞋搞不清,如果js是单线程的,那么谁去轮询大的Event loop事件队列?答案是浏览器会有单独的线程去处理这个队列。
Ajax异步请求是否真的异步?
很多童鞋搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?
其实请求确实是异步的,这请求是由浏览器新开一个线程请求(见前面的浏览器多线程)。当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的事件处理队列中等待处理。当浏览器空闲的时候出队列任务被处理,JavaScript引擎始终是单线程运行回调函数。javascript引擎确实是单线程处理它的任务队列,能理解成就是普通函数和回调函数构成的队列。
总结一下,Ajax请求确实是异步的,这请求是由浏览器新开一个线程请求,事件回调的时候是放入Event loop单线程事件队列等候处理。
setTimeout(func, 0)为什么有时候有用?
写js多的童鞋可能发现,有时候加一个setTimeout(func, 0)非常有用,为什么?难道是模拟多线程吗?错!前面已经说过了,javascript是JS运行在浏览器中,是单线程的,每个window一个JS线程,既然是单线程的,setTimeout(func, 0)神奇在哪儿?那就是告诉js引擎,在0ms以后把func放到主事件队列中,等待当前的代码执行完毕再执行,注意:重点是改变了代码流程,把func的执行放到了等待当前的代码执行完毕再执行。这就是它的神奇之处了。它的用处有三个:
- 让浏览器渲染当前的变化(很多浏览器UI render和js执行是放在一个线程中,线程阻塞会导致界面无法更新渲染)
- 重新评估”script is running too long”警告
- 改变执行顺序
非阻塞js的实现(non-blocking javascript)
defer
<script type="text/javascript" defer src="foo.js"></script>
async
<script type="text/javascript" async src="foo.js"></script>
然后第二种方法是动态加载js:
setTimeout(function(){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "foo.js";
var head = true; //加在头还是尾
if(head)
document.getElementsByTagName("head")[0].appendChild(script);
else
document.body.appendChild(script);
}, 0); //另外一个独立的动态加载js的函数
function loadJs(jsurl, head, callback){
var script=document.createElement('script');
script.setAttribute("type","text/javascript"); if(callback){
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
}
script.setAttribute("src", jsurl); if(head)
document.getElementsByTagName('head')[0].appendChild(script);
else
document.body.appendChild(script); }
单线程的JavaScript的更多相关文章
- JavaScript到底是不是单线程
JavaScript到底是不是单线程 JavaScript引擎 在了解计时器内部运作前,我们必须清楚一点,触发和执行并不是同一概念,计时器的回调函数一定会在指定delay的时间后被触发,但并不一定立即 ...
- Javascript引擎单线程机制及setTimeout执行原理说明
setTimeout用法在实际项目中还是会时常遇到.比如浏览器会聪明的等到一个函数堆栈结束后才改变DOM,如果再这个函数堆栈中把页面背景先从白色设为红色,再设回白色,那么浏览器会认为DOM没有发生任何 ...
- 细说JavaScript单线程的一些事
标签: JavaScript 单线程 首发地址:码农网<细说JavaScript单线程的一些事> 最近被同学问道 JavaScript 单线程的一些事,我竟回答不上.好吧,感觉自己的 Ja ...
- 从Javascript单线程谈Event Loop
假如面试回答js的运行机制时,你可能说出这么一段话:"Javascript的事件分同步任务和异步任务,遇到同步任务就放在执行栈中执行,而碰到异步任务就放到任务队列之中,等到执行栈执行完毕之后 ...
- 深入理解Javascript单线程谈Event Loop
假如面试回答js的运行机制时,你可能说出这么一段话:"Javascript的事件分同步任务和异步任务,遇到同步任务就放在执行栈中执行,而碰到异步任务就放到任务队列之中,等到执行栈执行完毕之后 ...
- 关于javascript的单线程和异步的一些问题
关于js单线程和异步方面突然就糊涂了,看别人的文章越看越糊涂,感觉这方面是个坑,跳进去就不好跳出来.再去看,看着看着感觉自己明白了一些东西,也不知道对不对,反正是暂时把自己说服了,这样理解能理解的通, ...
- JavaScript 的异步和单线程
问题 Q:下面的代码是否能满足sleep效果? var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert( ...
- JavaScript单线程(setTimeout,setInterval)
今天看到这篇文章,学到了不少东西 特此发出来 和大家分享 JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执 ...
- 【前端知识体系-JS相关】深入理解JavaScript异步和单线程
1. 为什么JavaScript是单线程? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊. Jav ...
随机推荐
- orcle 索引的使用
2.4.3.1. 索引的概念 数据库中的索引与书籍中的索引类似,在一本书中,利用索引可以快速查找所需信息, 无须阅读整本书.在数据库中,索引使数据库程序无须对整个表进行扫描, 就可以在其中找到所需数据 ...
- lvs讲解
作者写的就是好呀,简单明了,安逸的我也不知道早点看看,非得等到找工作了,在这里临时抱佛脚,以后再过来添加我自己的总结 http://www.linuxvirtualserver.org/zh/
- vue-devtools vue开发调试神器
前言: 由于vue是数据驱动的,所以这就存在在开发调试中查看DOM结构并不能解析出什么. 但是借助vue-devtools插件,我们就可以很容易的对数据结构进行解析和调试. 一.下载chrome扩展插 ...
- 基于封装通用的EF CRUD 的操作
1. Entity Framework是Microsoft的ORM框架,随着 Entity Framework 不断的完善强化已经到达了EF 6.0+ 还是非常的完善的,目前使用的比例相对于其他OR ...
- CJOJ 2022 【一本通】简单的背包问题(搜索)
CJOJ 2022 [一本通]简单的背包问题(搜索) Description 设有一个背包可以放入的物品重量为S,现有n件物品,重量分别是w1,w2,w3,-wn. 问能否从这n件物品中选择若干件放入 ...
- php 批量进行复制文件
php 批量进行复制文件 1.前言 目标:php批量进行复制指定的目录文件夹下所有文件复制到另一个文件夹下 所使用的的php函数:is_dir,opendir,readdir,scandir,mkdi ...
- Python面向对象编程(三)
封装 1.为什么要封装? 封装就是要把数据属性和方法的具体实现细节隐藏起来,只提供一个接口.封装可以不用关心对象是如何构建的 2.封装包括数据的封装和函数的封装,数据的封装是为了保护隐私,函数的封装是 ...
- 一次花费了一两个小时的mysql问题排查
晚上把博客迁了个服务器,新建用户的时候遇到问题了. 关于mysql的问题. 前置操作 建了两个用户,一个laravel,一个blog用户以及他们的同名数据库. 建好之后,命令行下面连接mysql服务, ...
- Ant 之bulid.xml详解
ANT build.xml文件详解(一) Ant的概念 可能有些读者并不连接什么是Ant以及入可使用它,但只要使用通过Linux系统得读者,应该知道 make这个命令.当编译Linux内核及一些软件的 ...
- php nginx反向代理
一.概念理解 1.代理服务器 代理服务器,客户机在发送请求时,不会直接发送给目的主机,而是先发送给代理服务器,代理服务接受客户机请求之后,再向主机发出,并接收目的主机返回的数据,存放在代理服务器的硬盘 ...