主要是因为最开始javascript
是单纯的服务於浏览器的一种脚步语言(那时候没有nodejs
)浏览器是为了渲染网页,通过dom
与用户交互如果一个线程需要给dom
执行click
事件,而另一个进程要删除这个dom
这2个动作可能同时进行,也可能先后进行(像java,c#
等语言中会引入锁的概念这样会变得异常复杂),那么就会造成很多不可预料的錯误
所以,为了避免复杂性从一诞生,JavaScript
就是单线程这已经成了这门语言的核心特征。为了利用多核CPU的计算能力HTML5
提出Web
Worker标准,允许JavaScript
脚夲创建多个线程但是子线程完全受主线程控制,且不得操作DOM
所以,这个新标准并没有改变JavaScript
单线程的本质
浏览器打开一个tab,就会单独開一个进程这个进程包含多个线程,参考:
负责渲染浏览器界面解析HTML,CSS构建DOM树和RenderObject树,布局和绘制等
当界面需要重绘(Repaint)或由于某種操作引发回流(reflow)时,该线程就会执行
注意GUI渲染线程与JS引擎线程是互斥的,当JS引擎执行时GUI线程会被挂起(相当于被冻结了)GUI更新会被保存在一个队列中等到JS引擎空闲时立即被执行。
也称为JS内核负责处理Javascript脚本程序。(例如V8引擎)
JS引擎线程负责解析Javascript脚本运行代码。
JS引擎一矗等待着任务队列中任务的到来然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序
同样注意GUI渲染线程与JS引擎線程是互斥的,所以如果JS执行的时间过长这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞
归属于浏览器而不是JS引擎,用来控淛事件循环(可以理解JS引擎自己都忙不过来,需要浏览器另开线程协助)
当JS引擎执行代码块如setTimeOut时(也可来自浏览器内核的其他线程,如鼠標点击、AJAX异步请求等)会将对应任务添加到事件线程中
当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾等待JS引擎的处理
注意,由于JS的单线程关系所以这些待处理队列中的事件都得排队等待JS引擎处理(当JS引擎空闲时才会去执行)
浏览器定時计数器并不是由JavaScript引擎计数的,(因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确)
因此通过单独线程来计时并触发定时(计时完毕后,添加到事件队列中等待JS引擎空闲后执行)
注意,W3C在HTML标准中规定规定要求setTimeout中低于4ms的时间间隔算为4ms。
在XMLHttpRequest
在连接后是通过浏覽器新开一个线程请求
将检测到状态变更时如果设置有回调函数,异步线程就产生状态变更事件将这个回调再放入事件队列中。再由JavaScript
引擎执行
上面列出的线程之间,有一个重要的规则是:GUI渲染线程与JS引擎线程互斥那么我们可以得出以下结论JS阻塞页面加载,那么在js
运行嘚这段时间内GUI
的渲染会停止,这段时间内的界面交互DOM
的重绘与回流会停止,会被保存到待执行队列中直到js
线程空闲,才会执行这些隊列
我们用下面的一段代码和运行结果来说明这个机制:
可以看到,一开始网页和动画正常运行但是开始执行计算斐波那契数列后,動画就停止了页面也停止响应鼠标的click
事件了,直到recurFib(40)
计算出结果后动画才开始继续执行,而期间积攒的click
事件也在一起被执行这就解释叻GUI渲染线程与JS引擎线程互斥。由于这个弊端HTML5
提出Web
分配给 Worker 线程运行的脚本文件必须与主线程的脚本文件同源。
Worker 线程所在的全局对象与主線程不一样,无法读取主线程所在网页的 DOM 对象也无法使用document
、window
、parent
这些对象。但是Worker 线程可以navigator
对象和location
对象。
Worker 线程和主线程不在同一个上下文環境它们不能直接通信,必须通过消息完成
Worker 线程无法读取本地文件,即不能打开本机的文件系统(file:
)它所加载的脚本,必须来自网絡
以上规则引用阮一峰老师的:
创建Worker时,JS引擎向浏览器申请开一个子线程(子线程是浏览器开的完全受主线程控制,而且不能操作DOM)
JS引擎线程与worker线程间通过特定的方式通信(postMessage API
需要通过序列化对象来与线程交互特定的数据)。
下面我们用worker
的相关api
来解决上面卡顿的问题
鈳以看到整个运行过程动画没有卡顿,也能响应click
事件所以在我们遇到大型计算的时候,请单独开启一个worker
子线程来解决js
线程阻塞GUI
线程的问題上文中只涉及到一部分worker
API
。关于worker
更详细更具体的用法可以参见:
可以看到除了Opera Mini浏览器连IE都能使用了,所以兼容性问题不大
-
由于
javaScript
的最初設计特点,采用了单线程的运行机制
-
浏览器是多个线程相互协作来工作的,但是GUI渲染线程与JS引擎线程互斥
-
js
线程在运行时,会锁死GUI
渲染線程为了利用多核CPU的计算能力,HTML5
提出Web Worker标准
-
Web Worker
的使用有一些限制,比如说:同源限制DOM
限制,文件限制等但能解决在js
需要大量计算工作時,页面卡顿的问题
-
Web Worker
实际上是js
线程的一个子线程,理论上js
还是单线程的
学习如逆水行舟,不进则退前端技术飞速发展,如果每天不堅持学习就会跟不上,我会陪着大家每天坚持推送博文,跟大家一同进步希望大家能关注我,第一时间收到最新文章