1. 用户输入
用户输入 URL 并回车, 意味这当前页面即将被替换成新到页面
当前页面执行 beforeunload
事件
beforeunload
事件允许页面在退出之前执行一些数据清理操作
- 还可以询问用户是否要离开当前页面, 比如未提交的表单
- 用户可以通过
beforeunload
事件来取消导航, 让浏览器不再执行后续工作
2. URL 请求过程
浏览器进程会通过进程间通信 (IPC) 把 URL 请求发送至网络进程
网络进程接收到 URL 请求后, 会发起真正的 URL 请求
查找是否有本地缓存. 如果有, 直接将缓存返回给浏览器进程; 如果没有, 那么进入网络请求流程.
网络请求流程
- 进行 DNS 解析, 获得 ip 地址
- 如果是 HTTPS, 还需要建立 TLS 连接
- 利用 IP 地址和服务器建立 TCP 连接
- 连接建立之后, 浏览器构建请求行、请求头信息, 并把域名相关的 Cookie 等数据附加到请求头中, 然后向服务器发送请求
- 服务器接收到请求后, 会根据请求信息生成响应数据 (响应行、响应头和响应体等内容), 并发送给网络进程
- 网络进程接收到响应行和响应头, 就开始解析响应头的内容
网络进程解析响应头
(1) 重定向
- 如果状态码是 301 或 302, 网络进程会读取 Location 字段中重定向的地址, 重新发起 HTTP 或 HTTPS 请求
- 如果状态码是 200, 表示浏览器可以继续处理该请求
(2) 响应数据类型处理
浏览器会根据
Content-Type
的值来决定如何处理响应体的内容Content-Type
取值
Content-Type: text/html
表示返回的是 HTML 格式内容, 那么浏览器会继续进行导航流程Content-Type: application/json
表示返回的是 JSON 格式内容Content-Type: application/octet-stream
表示返回的数据是字节流类型, 浏览器会按照下载类型来处理, 那么该请求会被提交给下载管理器3. 准备渲染进程
- 通常情况下, 浏览器会为每个新页面配套创建一个新的渲染进程
- 如果从 A 页面打开 B 页面, 并且 A 和 B 都属于同一站点, 那么 B 页面复用 A 页面的渲染进程
- 官方把这个默认策略叫
process-per-site-instance
同一站点: 相同的协议和根域名
渲染进程准备好之后, 还不能立即进入文档解析状态, 因为此时的文档数据还在网络进程中, 并没有提交给渲染进程, 所以下一步就进入来提交文档的阶段
4. 提交文档
提交文档: 浏览器进程将网络进程接收到 HTML 数据提交给渲染进程
提交文档流程
- 浏览器进程接收到网络进程的响应头数据之后, 便向渲染进程发起 "提交文档" 的消息
- 渲染进程接收到 "提交文档" 的消息后, 会和网络进程建立传输数据的 "管道"
- 等文档数据传输完成之后, 渲染进程会返回 "确认提交" 的消息给浏览器进程
- 浏览器进程在收到 "确认提交" 的消息后, 会更新浏览器界面状态, 包括安全状态、地址栏的 URL、前进后退的历史状态, 并更新 Web 页面
这也解释了为什么在浏览器地址栏中输入一个地址后, 之前的页面没有立马消失
5. 渲染阶段
一旦文档被提交, 渲染进程便开始页面解析和子资源加载了
按照渲染的时间顺序, 流水线可分为
1. 构建 DOM 树
经过这一过程 DOM 树虽然生成好了, 但是 DOM 节点的样式依然是未知的
要让 DOM 节点拥有正确的样式, 就需要样式计算了
2.样式计算 (Recalculate Style)
样式计算阶段大体分为三步
1.把 CSS 转换为浏览器能够理解的结构 —— styleSheets
CSS 样式来源主要有三种
- link 引入的外部 CSS 文件
<style>
标签内的 CSS
- 元素的内联样式 style 属性
和 HTML 文件一样, 浏览器无法直接理解这些纯文本 CSS 样式, 渲染引擎会将 CSS 文本转换为浏览器可以理解的结果 —— styleSheets
document.styleSheets
可以查看转换后的 styleSheets
2.转换样式表中的属性值, 使其标准化
很多属性, 如 2em、blue、bold, 这些类型数值不容易被渲染引擎理解
因此渲染引擎需要将所有值转换为容易理解、标准化的计算值
计算出 DOM 树中每个节点的具体样式
根据 CSS 的继承规则和层叠规则 (定义了如何合并来自多个源的属性值的算法) 计算出 DOM 树每个节点的具体样式
3.布局阶段
chrome 在布局阶段需要完成两个任务
1.创建布局树
因为 DOM 树包含很多不可见元素 (比如 head 标签, 使用了 display: none 元素), 所以在显示之前, 还需要额外构建一棵只包含可见元素布局树
构建布局树流程
- 遍历 DOM 树中的所有可见节点, 并把这些节点加到布局树中
- 不可见节点会被忽略掉
2.布局计算
TODO