js单线程理解
今天看了一些文章,让我对
js
单线程有了一些理解,甚至是颠覆性的,有空就记录一下,和大家分享一下,一起成长进步
-
js
单线程是js
语言的特性吗? -
setTimeout
函数哪怕设置执行的时间为0,看起来依然像延迟执行一样,是因为异步?还是放到了js
其他线程执行了?
针对第一问题:js单线程是js语言的特性吗?
首先我们来看一下浏览器在进行渲染的时候,是如何分配工作的:
Chrome
浏览器使用多个进程来隔离不同的网页,在Chrome
中打开一个网页相当于起了一个进程,每个tab
网页都有由其独立的渲染引擎实例。因为如果非多进程的话,如果浏览器中的一个tab
网页崩溃,将会导致其他被打开的网页应用。另外相对于线程,进程之间是不共享资源和地址空间的,所以不会存在太多的安全问题,而由于多个线程共享着相同的地址空间和资源,所以会存在线程之间有可能会恶意修改或者获取非授权数据等复杂的安全问题。
在内核控制下各线程相互配合以保持同步,一个浏览器通常由以下常驻线程组成:
-
GUI
渲染线程:
GUI
渲染线程负责渲染浏览器界面HTML
元素,当界面需要重绘(Repaint
)或由于某种操作引发回流(reflow
)时,该线程就会执行。在Javascript
引擎运行脚本期间,GUI
渲染线程都是处于挂起状态的,也就是说被冻结了。
-
JavaScript
引擎线程:
JS
为处理页面中用户的交互,以及操作DOM
树、CSS
样式树来给用户呈现一份动态而丰富的交互体验和服务器逻辑的交互处理。如果JS
是多线程的方式来操作这些UI DOM
,则可能出现UI
操作的冲突;如果JS
是多线程的话,在多线程的交互下,处于UI中的DOM节点就可能成为一个临界资源,假设存在两个线程同时操作一个DOM
,一个负责修改一个负责删除,那么这个时候就需要浏览器来裁决如何生效哪个线程的执行结果,当然我们可以通过锁来解决上面的问题。但为了避免因为引入了锁而带来更大的复杂性,JS
在最初就选择了单线程执行。
- 定时触发器线程:
浏览器定时计数器并不是由
JS
引擎计数的, 因为JS
引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确, 因此通过单独线程来计时并触发定时是更为合理的方案。
- 事件触发线程:
当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待
JS
引擎的处理。这些事件可以是当前执行的代码块如定时任务、也可来自浏览器内核的其他线程如鼠标点击、AJAX
异步请求等,但由于JS
的单线程关系所有这些事件都得排队等待JS
引擎处理。
- 异步
http
请求线程:
在
XMLHttpRequest
在连接后是通过浏览器新开一个线程请求,将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到JS
引擎的处理队列中等待处理。
- 看到这里,我们理解了,
js
是单线程的原因不是js语言的特性,是浏览器只给js
分配了一个线程的原因。js
是单线程只是我们的简单的说法。
针对第二问题:setTimeout函数哪怕设置执行的时间为0,看起来依然像延迟执行一样,是因为异步?还是放到了js其他线程执行了?
- 懂了第一问题以后,第二个问题也很好理解了,
setTimeout
函数是放在定时触发器线程的,当计时结束,开始执行回调函数的时候,是把代码放到js队列里面,而js是按照队列执行的,所以即使是setTimeout
函数哪怕设置执行的时间为0,也不会立刻执行,因为要按照队列执行,这个不是异步的原因。
总结: js是单线程的原因不是js语言的特性,是浏览器只给js分配了一个线程的原因;
setTimeout
函数是放在定时触发器线程,即使结束,代码放到js
队列按照顺序执行,造成异步执行的效果。
网友评论