浏览器架构
导航流程
从输入URL到页面展示,这中间发生了什么?
1,用户输入url并回车
2,浏览器进程检查url,组装协议,构成完整的url
3,浏览器进程通过进程间通信(IPC)把url请求发送给网络进程
4,网络进程接收到url请求后检查本地缓存是否缓存了该请求资源,如果有则将该资源返回给浏览器进程
5,如果没有,网络进程向web服务器发起http请求(网络请求),请求流程如下:
5.1 进行DNS解析,获取服务器ip地址,端口
5.2 利用ip地址和服务器建立tcp连接
5.3 构建请求头信息
5.4 发送请求头信息
5.5 服务器响应后,网络进程接收响应头和响应信息,并解析响应内容
6,网络进程解析响应流程;
6.1 检查状态码,如果是301/302,则需要重定向,从Location自动中读取地址,重新进行第4步,如果是200,则继续处理请求。
6.2 200响应处理:
检查响应类型Content-Type,如果是字节流类型,则将该请求提交给下载管理器,该导航流程结束,不再进行
后续的渲染,如果是html则通知浏览器进程准备渲染进程准备进行渲染。
7,准备渲染进程
7.1 浏览器进程检查当前url是否和之前打开的渲染进程根域名是否相同,如果相同,则复用原来的进程,如果不同,则开启新的渲染进程
8. 传输数据、更新状态
8.1 渲染进程准备好后,浏览器向渲染进程发起“提交文档”的消息,渲染进程接收到消息和网络进程建立传输数据的“管道”
8.2 渲染进程接收完数据后,向浏览器发送“确认提交”
8.3 浏览器进程接收到确认消息后更新浏览器界面状态:安全、地址栏url、前进后退的历史状态、更新web页面。
渲染流程
按照渲染的时间顺序,流水线可分为如下几个子阶段:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。
-
构建 DOM 树: 在 HTML 页面内容被提交给渲染引擎之后,渲染引擎首先将 HTML 解析为浏览器可以理解的 DOM;
-
样式计算:
根据 CSS 样式表,计算出 DOM 树所有节点的样式;
转换样式表中的属性值,使其标准化。
计算出 DOM 树中每个节点的具体样式 -
布局阶段:构建一棵只包含可见元素布局树,计算每个元素的几何坐标位置,并将这些信息保存在布局树中。
-
分层:渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree),图层叠加后合成了最终的页面。
第一点,拥有层叠上下文属性的元素会被提升为单独的一层。 图层参考文章.
第二点,需要剪裁(clip)的地方也会被创建为图层。 -
绘制:把一个图层的绘制拆分成很多小的绘制指令,生成记录绘制顺序和绘制指令的列表
-
分块和栅格化:分块是合成线程将图层划分为图块的过程, 栅格化是指将图块转换为位图的过程。合成线程会按照视口附近的图块来优先生成位图。使用 GPU 生成位图的过程叫快速栅格化,生成的位图被保存在 GPU 内存中。
-
合成和显示:浏览器进程将其页面内容绘制到内存中,最后再将内存显示在屏幕上。
如何减少重排重绘
重排:通过 JavaScript 或者 CSS 修改元素的几何位置属性,例如改变元素的宽度、高度等,那么浏览器会触发重新布局。
重绘:通过 JavaScript 更改某些元素的背景颜色等,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。
合成:使用了 CSS 的 transform 来实现动画效果,这可以避开重排和重绘阶段,直接在非主线程上执行合成动画操作。相对于重绘和重排,合成能大大提升绘制效率。
- 使用 class 操作样式,而不是频繁操作 style
- 避免使用 table 布局
- 批量dom 操作,通过虚拟dom层计算出操作总得差异,一起提交给浏览器,例如 createDocumentFragment,或者使用框架,例如 React
- Debounce window resize 事件
- 对 dom 属性的读写要分离
- will-change: transform 做优化