浏览器 进程/线程 介绍
进程 线程
浏览器多进程,每打开一个 tab 就多一个进程,browser 进程 浏览器的主进程 只有一个
- 负责各个页面的管理,创建和销毁其他进程
- 网络资源的管理,下载等
- 负责浏览器界面显示,与用户交互。如前进,后退等
GPU 进程:最多一个,用于 3D 绘制等
浏览器渲染进程(浏览器内核)(Renderer 进程,内部是多线程的
[页面的渲染,JS 的执行,事件的循环] 都在这个进程里,默认每个 Tab 页面一个进程,互不影响,主要作用为 页面渲染,脚本执行,事件处理等
多进程的优势
- 防止单 page crash 影响整个浏览器
- 避免第三方插件 crash 影响整个浏览器
- 多进程充分利用多核优势
- 方便使用沙盒模型隔离插件等进程,提高浏览器稳定性
渲染进程内部是有多线程的看看哪些线程吧
1. GUI 渲染线程
- 负责渲染浏览器界面,解析 HTML,CSS,构建 DOM 树和 RenderObject 树,布局和绘制等。
- 当界面需要重绘(Repaint)或由于某种操作引发回流(reflow) 时,该线程就会执行
- GUI 渲染线程与 JS 引擎线程是互斥的 当 JS 引擎执行时 GUI 线程会被挂起(相当于被冻结了),GUI 更新会被保存在一个队列中等到 JS 引擎空闲时立即被执行。
2. JS 引擎线程
- 也称为 JS 内核,负责处理 Javascript 脚本程序
- JS 引擎线程负责解析 Javascript 脚本,运行代码。
- GUI 渲染线程与 JS 引擎线程是互斥的,所以如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞。
3. 事件触发线程
- 当 JS 引擎执行代码块如 setTimeOut 时(也可来自浏览器内核的其他线程,如鼠标点击、AJAX 异步请求等),会将对应任务添加到事件线程中
- 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待 JS 引擎的处理
由于 JS 的单线程关系,所以这些待处理队列中的事件都得排队等待 JS 引擎处理(当 JS 引擎空闲时才会去执行)
4. 定时触发器线程
传说中的 setInterval 与 setTimeout 所在线程,为什么要单独的定时器线程?因为 JavaScript 引擎是单线程的,如果处于阻塞线程状态就会影响记计时的准确,因此很有必要单独开一个线程用来计时。
5. 异步 http 请求线程
在 XMLHttpRequest 在连接后是通过浏览器新开一个线程请求,将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。再由 JavaScript 引擎执行。
WebWorker
- 创建 worker 时,js 引擎向浏览器申请一个子线程, 子线程完全由浏览器控制 所以不能操作 dom
- js 引擎线程与 worker 子线程通过特定的方式通信,需要通过序列化对象来与线程交互特定的数据
- JS 引擎是单线程的,这一点的本质仍然未改变,Worker 可以理解是浏览器给 JS 引擎开的外挂,专门用来解决那些大量计算问题。
WebWorker 与 SharedWorker
WebWorker 只属于某个页面,不会和其他页面的 Render 进程(浏览器内核进程)共享,所以 Chrome 在 Render 进程中(每一个 Tab 页就是一个 render 进程)创建一个新的线程来运行 Worker 中的 JavaScript 程序。
SharedWorker 是浏览器所有页面共享的,不能采用与 Worker 同样的方式实现,因为它不隶属于某个 Render 进程,可以为多个 Render 进程共享使用,sharedWorker 由单独的进程管理, WebWorker 只是属于 render 进程下的一个线程。
- css 加载是否会阻塞 dom 树渲染?
- css 是由单独的下载线程异步下载的。
- css 加载不会阻塞 DOM 树解析(异步加载时 DOM 照常构建)
但会阻塞 render 树渲染(渲染时需等 css 加载完毕,因为 render 树需要 css 信息)
普通图层和复合图层
GPU 中每个复合图层是单独绘制的 所以不相互影响,普通文档流内可以理解成一个复合图层 这里称为默认复合层,里面不管添加多少元素,其实都是在同一个复合图层中),absolute fixed 布局 脱离文档流 还在这个复合图层。
通过硬件加速,声明一个新的复合图层 他会单独分配资源, 当然也会脱离文档流,这样这个复合图层怎么改变,也不会影响默认复合层的重排重绘。
如何生成新的复合图层
硬件加速
最常用的方式:translate3d、translateZ,opacity 属性/过渡动画(需要动画执行的过程中才会创建合成层,动画没有开始或结束后元素还会回到之前的状态),<video><iframe><canvas><webgl>等元素
其它,譬如以前的 flash 插件
absolute 和硬件加速的区别
absolute 虽然脱离文档流 但是仍然在默认复合层内,就算 absolute 中信息改变时不会改变普通文档流中的 render 树,但是浏览器最终绘制的时候还是会整个复合层绘制,所以 absolute 中信息的改变,仍然会影响整个复合层的绘制。
硬件加速是在另一个复合层中,他的信息改变不会引起原来的复合层改变(当然,内部肯定会影响属于自己的复合层)仅仅是引发最后的合成(输出视图)
复合图层的作用
一般一个元素开启硬件加速后会变成复合图层,可以独立于普通文档流中,改动后可以避免整个页面重绘,提升性能量,但是不要大量使用复合图层,否则由于资源消耗过度,页面反而会变的更卡
Event loop
JS 中分为两种任务类型:macrotask 和 microtask 在 ECMAScript 中,microtask 称为 jobs,macrotask 可称为 task,macrotask 中的事件都是放在一个事件队列里面,是由事件触发线程维护。
可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)
- 每一个 task 会从头到尾将这个任务执行完毕,不会执行其它
- 浏览器为了能够使得 JS 内部 task 与 DOM 任务能够有序的执行,会在一个 task 执行结束后,在下一个 task 执行开始前,对页面进行重新渲染 (task->渲染->task->...)
microtask 中所有微任务都是添加到微任务队列中,等待当前 macrotask 执行完毕后 这个队列由 js 引擎线程自己维护
- 在当前 task 任务后,下一个 task 之前,在渲染之前
- 所以它的响应速度相比 setTimeout(setTimeout 是 task)会更快,因为无需等渲染
- 在某一个 macrotask 执行完后,就会将在它执行期间产生的所有 microtask 都执行完毕(在渲染前)
microtask:Promise,process.nextTick 等
macrotask:主代码块,setTimeout,setInterval 等(可以看到,事件队列中的每一个事件都是一个 macrotask)
总结一下运行机制
- 执行一个宏任务栈中(没有就从事件队列中获取)
- 执行过程中如果遇到微任务,就将它添加到微任务的任务队列中
- 宏任务执行完毕后,立即执行当前微任务队列中的所有微任务(依次执行
- 当前宏任务执行完毕,开始检查渲染,然后 GUI 线程接管渲染
- 渲染完毕后,JS 线程继续接管,开始下一个宏任务(从事件队列中获取)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: CSS 冷门知识点
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论