浏览器URL输入到页面展示
用户输入
- 用户在地址栏按下回车,检查输入(关键字 or 符合 URL 规则),组装完整 URL
- 确认前(点击回车),当前页面执行 onbeforeunload 事件
- 浏览器进入加载状态
URL请求
- 浏览器进程通过 进程间通信(IPC)把URL请求发送至网络进程
- 查找资源缓存
网络进程会查找本地缓存是否缓存了在有效期内的资源,若有,则返回到浏览器进程
- DNS解析(查询 DNS 缓存)
- 进入 TCP 队列(单个域名 TCP 连接数量限制)
- 创建 TCP 连接(三次握手)
- 如果是HTTPS,则 HTTPS 建立 TLS 连接(client hello, server hello, pre-master key 生成『对话密钥』)
- 发送 HTTP 请求(请求行
方法、URL、协议
、请求头 Cookie 等,请求体 POST) - 服务端接受请求并响应(响应行
协议、状态码、状态消息
、响应头、响应体等)
状态码 301 / 302,根据响应头中的 Location 重定向,重新开始从开始全过程
状态码 200,根据响应头中的 Content-Type 决定如何响应(下载文件、加载资源、渲染 HTML)
- 准备渲染
准备渲染进程
- 根据是否为同一进程(相同的协议和根域名),决定是否复用渲染进程
- 浏览器进程接收到网络进程的响应头数据,向渲染进程发送『提交文档』消息
- 渲染进程收到『提交文档』消息后,与网络进程建立传输数据的『通道』
- 传输完成后,渲染进程返回『确认提交』消息给浏览器进程
- 浏览器接收『确认提交』消息后,移除旧文档,更新界面、地址栏、历史导航状态等
- 开始渲染
渲染
渲染流水线
构建DOM树
- 渲染引擎接收HTML文档数据
- HTML解析器解析数据
- 输出DOM数据结构(DOM树)
样式计算
- 渲染引擎接收CSS文本数据
css样式来源: link引用的外部样式
<style>
标记内的的css
元素内联样式
- 将CSS文本转换为styleSheets(样式表)
- 将样式表中属性值标准化,(生成DOM树后)依据样式表计算每个节点的具体样式(层叠、继承等,并保存在 ComputedStyle 结构中)
- 输出styleSheets(CSSOM)
布局
计算DOM中可见元素的几何位置
- 创建布局树(遍历DOM树中的所有可见节点,并把这些节点加入到布局树中)
- 根据样式表等进行布局计算,结果写入布局树
- 最终生成布局树(render tree)
分层
- 将布局树依据规则分成图层
拥有层叠上下文属性的元素会被提升为单独一层(明确定位属性、透明属性、CSS滤镜、z-index等) 需要裁剪的地方会创建图层 没有图层的DOM节点从属于父节点图层
- 最终生成图层树(LayerTree)
绘制
渲染引擎对每个图层进行绘制
- 每一个图层对应生成一个绘制列表(图层的绘制会拆分为很多绘制指令,绘制指令按照顺序组成绘制列表)
- 将绘制列表提交给合成线程
- 合成线程将图层划分为图块
- 光栅化,将图块转换为位图
优先生成视口附近的位图 图块栅格化在栅格化线程池中进行 通常,栅格化过程会使用GPU加速,图块生成的位图会保存在GPU内存
- 光栅化完成后,合成线程生成绘制图块的命令---DrawQuad,并提交给浏览器进程
- viz组件接收命令,将内容绘制到内存中(显存的后缓存区)
- 最终显示到显示器上
主线程:DOM树、计算样式、布局、分层、绘制
非主线程:图层转换图块、光栅化、DrawQuad、显示
相关概念
重排
更新元素的几何属性
通过js或者css修改元素的几何位置(宽高等),浏览器触发重新布局
重排需要更新完整的渲染流水线,开销最大
重绘
更新元素的绘制属性
修改元素的绘制属性(背景颜色等),会跳过布局阶段(布局和分层),直接进入绘制阶段
重绘开销相对重排较小,但也有消耗
合成
更改既不需要布局也不需要绘制的属性,会跳过布局和绘制阶段,只执行非主线程的合成操作(css的transform等)
合成操作不占用浏览器主线程,相较重排和重绘效率极大提升