Chrome 架构
进程与线程
每一个执行中的程序可以理解为 进程, 一个进程由多个线程组成
一个进程中任意一个线程出错, 就会导致整个进程出错
一个进程中的所有线程共享进程中的数据
不同进程之间的内容相互隔离
关闭进程时, 进程中的所有线程也会关闭
进程
进程是 CPU 资源分配的最小单位
线程
线程是 CPU 调度的最小单位
区别
进程是资源分配的最小单位,线程是程序执行的最小单位
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此 CPU 切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点
但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间
单进程浏览器架构
进程包含 网络、插件、js 运行环境、渲染引擎等模块
缺点
- 不稳定
一个模块的崩溃会引起整个浏览器的崩溃
不流畅
不安全
多进程浏览器架构
最新的 Chrome 浏览器包括:1 个浏览器(Browser)主进程、1 个 GPU 进程、1 个网络(NetWork)进程、多个渲染进程和多个插件进程
浏览器进程
界面显示、用户交互、子进程管理,同时提供存储等功能
渲染进程
核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下
渲染进程中的几种线程:
- GUI 渲染线程
- JavaScript 引擎线程
- 定时器触发线程
- 事件触发线程
- 异步 http 请求线程
GPU 进程
UI 界面都选择采用 GPU 来绘制
网络进程
主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程
插件进程
主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响
渲染流程
整个渲染流程分为: 构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成
- 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
- 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
- 创建布局树,并计算元素的布局信息。
- 对布局树进行分层,并生成分层树。
- 为每个图层生成绘制列表,并将其提交到合成线程。
- 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
- 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
- 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上
构建 DOM 树
解析 HTML 输出 DOM 树
样式计算
通过 样式表, CSS 继承规则,CSS 层叠规则 计算出每个 DOM 节点的具体样式
解析 CSS 文件
标准化样式表属性
计算 DOM 节点样式
布局
创建布局树
遍历 DOM 树中所有可见节点,并添加到布局中
布局计算
计算节点坐标
分层
拥有层叠上下文属性的元素会被提升为单独的一层
- position: fixed
- z-index: 2
- filter
- opacity
需要裁剪的地方也会被创建为图层
图层绘制
栅格化
记录绘制顺序和绘制指令的列表
合成与显示
渲染优化
重排
布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
元素的几何属性修改会触发浏览器重新布局
- 添加或删除可见的 DOM 元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
- 浏览器的窗口尺寸变化
重绘
当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制
元素绘制属性变化, 触发重绘, 重绘省去了布局和分层阶段,执行效率高于重排
- 颜色的修改
- 文本方向的修改
- 阴影的修改
直接合成阶段
无需布局和绘制, 只执行合成操作
其他
script defer async