前言
大家都知道js是基于单线程的,而这个线程就是浏览器的js引擎。但是浏览器内核是多线程,在内核控制下各线程相互配合工作。
1.浏览器内核常驻线程
浏览器 GUI 渲染线程
JavaScript 引擎线程
浏览器定时触发器线程
浏览器事件触发线程
浏览器 http 异步请求线程
(1)GUI渲染线程
GUI渲染线程负责渲染浏览器界面的HTML元素, 当界面需要重绘(repaint)或者由于某种操作引发回流(reflow)时,该线程就会执行。在Javascript引擎运行脚本期间,GUI渲染线程都是处于挂起状态的。
(2)Javascript引擎线程
Javascript引擎,也可以称为JS内核,主要负责处理Javascript脚本程序,例如V8引擎。Javascript引擎线程理所当然是负责解析Javascript脚本,运行代码。
ps:web worker只是允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。
(3)浏览器事件触发线程
接受浏览器里面的操作事件响应。如在监听到鼠标、键盘等事件的时候, 如果有事件句柄函数,就讲对应的任务压入队列。
(4)浏览器定时触发线程
浏览器模型定时计数器并不是由JavaScript引擎计数的, 因为JavaScript引擎是单线程的, 如果处于阻塞线程状态就会影响记计时的准确, 它必须依赖外部来计时并触发定时。
(5)浏览器 http 异步请求线程
在XMLHttpRequest在连接后是通过浏览器新开一个线程请求, 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到 JavaScript引擎的处理队列中等待处理。
2.事件驱动(event driven)机制
事件驱动一般通过事件循环(event loop)和事件队列(event queue)来实现的。
假定浏览器中有一个专门用于事件调度的实例(该实例可以是一个线程,可以称之为事件分发线程event dispatch thread),该实例的工作就是一个不结束的循环,从事件队列中取出事件,处理所有很事件关联的回调函数(event handler)。
注意回调函数是在Javascript的主线程中运行的,而非事件分发线程中,以保证事件处理不会发生阻塞。
如果队列非空,引擎就从队列头取出一个任务,直到该任务处理完,即返回后引擎接着运行下一个任务, 在任务没返回前队列中的其它任务是没法被执行的。
browershell.png
Javascript引擎线程的运行机制
(1)所有同步任务都在主线程上执行,形成一个执行栈。
(2)主线程之外,还存在一个”任务队列”。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件。
(3)一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
3.GUI 渲染线程 与 JavaScript引擎线程是互斥的
由于JavaScript是可操纵DOM的,如果在修改这些元素属性同时渲染界面(即JavaScript线程和UI线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与JavaScript引擎为互斥的关系,当JavaScript引擎执行时GUI线程会被挂起,GUI更新会被保存在一个队列中等到引擎线程空闲时立即被执行。
作者:pattyzzh
链接:https://www.jianshu.com/p/25cf0edea38e
共同学习,写下你的评论
评论加载中...
作者其他优质文章