# 导航流程:从输入 URL 到页面展示,这中间发生了什么
- 用户输入 URL,浏览器会根据用户输入的信息判断是搜索还是网址,如果是搜索内容,就将搜索内容+默认搜索引擎合成新的 URL;如果用户输入的内容符合 URL 规则,浏览器就会根据 URL 协议,在这段内容上加上协议合成合法的 URL
- 用户输入完内容,按下回车键,浏览器导航栏显示 loading 状态,但是页面还是呈现前一个页面,这是因为新页面的响应数据还没有获得
- 浏览器进程浏览器构建请求行信息,会通过进程间通信(IPC)将 URL 请求发送给网络进程 GET /index.html HTTP1.1
- 网络进程获取到 URL,先去本地缓存中查找是否有缓存文件,如果有,拦截请求,直接 200 返回;否则,进入网络请求过程
- 网络进程请求 DNS 返回域名对应的 IP 和端口号,如果之前 DNS 数据缓存服务缓存过当前域名信息,就会直接返回缓存信息;否则,发起请求获取根据域名解析出来的 IP 和端口号,如果没有端口号,http 默认 80,https 默认 443。如果是 https 请求,还需要建立 TLS 连接。
- Chrome 有个机制,同一个域名同时最多只能建立 6 个 TCP 连接,如果在同一个域名下同时有 10 个请求发生,那么其中 4 个请求会进入排队等待状态,直至进行中的请求完成。如果当前请求数量少于 6 个,会直接建立 TCP 连接。
- TCP 三次握手建立连接,http 请求加上 TCP 头部——包括源端口号、目的程序端口号和用于校验数据完整性的序号,向下传输
- 网络层在数据包上加上 IP 头部——包括源 IP 地址和目的 IP 地址,继续向下传输到底层
- 底层通过物理网络传输给目的服务器主机
- 目的服务器主机网络层接收到数据包,解析出 IP 头部,识别出数据部分,将解开的数据包向上传输到传输层
- 目的服务器主机传输层获取到数据包,解析出 TCP 头部,识别端口,将解开的数据包向上传输到应用层
- 应用层 HTTP 解析请求头和请求体,如果需要重定向,HTTP 直接返回 HTTP 响应数据的状态 code301 或者 302,同时在请求头的 Location 字段中附上重定向地址,浏览器会根据 code 和 Location 进行重定向操作;如果不是重定向,首先服务器会根据 请求头中的 If-None-Match 的值来判断请求的资源是否被更新,如果没有更新,就返回 304 状态码,相当于告诉浏览器之前的缓存还可以使用,就不返回新数据了;否则,返回新数据,200 的状态码,并且如果想要浏览器缓存数据的话,就在相应头中加入字段: Cache-Control:Max-age=2000 响应数据又顺着应用层——传输层——网络层——网络层——传输层——应用层的顺序返回到网络进程
- 数据传输完成,TCP 四次挥手断开连接。如果,浏览器或者服务器在 HTTP 头部加上如下信息,TCP 就一直保持连接。保持 TCP 连接可以省下下次需要建立连接的时间,提示资源加载速度 Connection:Keep-Alive
- 网络进程将获取到的数据包进行解析,根据响应头中的 Content-type 来判断响应数据的类型,如果是字节流类型,就将该请求交给下载管理器,该导航流程结束,不再进行;如果是 text/html 类型,就通知浏览器进程获取到文档准备渲染
- 浏览器进程获取到通知,根据当前页面 B 是否是从页面 A 打开的并且和页面 A 是否是同一个站点(根域名和协议一样就被认为是同一个站点),如果满足上述条件,就复用之前网页的进程,否则,新创建一个单独的渲染进程
- 浏览器会发出“提交文档”的消息给渲染进程,渲染进程收到消息后,会和网络进程建立传输数据的“管道”,文档数据传输完成后,渲染进程会返回“确认提交”的消息给浏览器进程
- 浏览器收到“确认提交”的消息后,会更新浏览器的页面状态,包括了安全状态、地址栏的 URL、前进后退的历史状态,并更新 web 页面,此时的 web 页面是空白页
- 渲染进程对文档进行页面解析和子资源加载,HTML 通过 HTM 解析器转成 DOM Tree(二叉树类似结构的东西),CSS 按照 CSS 规则和 CSS 解释器转成 CSSOM TREE,两个 tree 结合,形成 render tree(不包含 HTML 的具体元素和元素要画的具体位置),通过 Layout 可以计算出每个元素具体的宽高颜色位置,结合起来,开始绘制,最后显示在屏幕中新页面显示出来
# 浏览器工作流程『从输入 URL 到页面展示』学习笔记
导航
用户输入
用户在地址栏按下回车,检查输入(关键字 or 符合 URL 规则),组装完整 URL;
具体流程是用户输入 URL,浏览器会根据用户输入的信息判断是搜索还是网址,如果是搜索内容,就将搜索内容+默认搜索引擎合成新的 URL;如果用户输入的内容符合 URL 规则,浏览器就会根据 URL 协议,在这段内容上加上协议合成合法的 URL
回车前,当前页面执行 onbeforeunload 事件;
浏览器进入加载状态。
URL 请求
- 浏览器进程通过 IPC 把 URL 请求发送至网络进程;
- 查找资源缓存(有效期内);
- DNS 解析(查询 DNS 缓存);
- 进入 TCP 队列(单个域名 TCP 连接数量限制);
- 创建 TCP 连接(三次握手);
- HTTPS 建立 TLS 连接(client hello, server hello, pre-master key 生成『对话密钥』);
- 发送 HTTP 请求(请求行[方法、URL、协议]、请求头 Cookie 等、请求体 POST);
- 接受请求(响应行[协议、状态码、状态消息]、响应头、响应体等);
- 状态码 301 / 302,根据响应头中的 Location 重定向;
- 状态码 200,根据响应头中的 Content-Type 决定如何响应(下载文件、加载资源、渲染 HTML)。
准备渲染进程
- 根据是否同一站点(相同的协议和根域名),决定是否复用渲染进程。
提交文档
- 浏览器进程接受到网路进程的响应头数据,向渲染进程发送『提交文档』消息;
- 渲染进程收到『提交文档』消息后,与网络进程建立传输数据『管道』;
- 传输完成后,渲染进程返回『确认提交』消息给浏览器进程;
- 浏览器接受『确认提交』消息后,移除旧文档、更新界面、地址栏,导航历史状态等;
- 此时标识浏览器加载状态的小圆圈,从此前 URL 网络请求时的逆时针选择,即将变成顺时针旋转(进入渲染阶段)。
渲染
渲染流水线
构建 DOM 树
- 输入:HTML 文档;
- 处理:HTML 解析器解析;
- 输出:DOM 数据解构。
样式计算
- 输入:CSS 文本;
- 处理:属性值标准化,每个节点具体样式(继承、层叠);
- 输出:styleSheets(CSSOM)。
布局(DOM 树中元素的计划位置)
- DOM & CSSOM 合并成渲染树;
- 布局树(DOM 树中的可见元素);
- 布局计算。
分层
- 特定节点生成专用图层,生成一棵图层树(层叠上下文、Clip,类似 PhotoShop 里的图层);
- 拥有层叠上下文属性(明确定位属性、透明属性、CSS 滤镜、z-index 等)的元素会创建单独图层;
- 没有图层的 DOM 节点属于父节点图层;
- 需要剪裁的地方也会创建图层。
绘制指令
- 输入:图层树;
- 渲染引擎对图层树中每个图层进行绘制;
- 拆分成绘制指令,生成绘制列表,提交到合成线程;
- 输出:绘制列表。
分块
- 合成线程会将较大、较长的图层(一屏显示不完,大部分不在视口内)划分为图块(tile, 256256, 512512)。
光栅化(栅格化)
- 在光栅化线程池中,将视口附近的图块优先生成位图(栅格化执行该操作);
- 快速栅格化:GPU 加速,生成位图(GPU 进程)。
合成绘制
- 绘制图块命令——DrawQuad,提交给浏览器进程;
- 浏览器进程的 viz 组件,根据 DrawQuad 命令,绘制在屏幕上。
相关概念
重排
- 更新了元素的几何属性(如宽、高、边距);
- 触发重新布局,解析之后的一系列子阶段;
- 更新完成的渲染流水线,开销最大。
重绘
- 更新元素的绘制属性(元素的颜色、背景色、边框等);
- 布局阶段不会执行(无几何位置变换),直接进入绘制阶段。
合成
- 直接进入合成阶段(例如 CSS 的 transform 动画);
- 直接执行合成阶段,开销最小。
# 总结:
1,用户输入 url 并回车,浏览器进程检查 url,组装协议,构成完整的 url
具体流程是用户输入 URL,浏览器会根据用户输入的信息判断是搜索还是网址,如果是搜索内容,就将搜索内容+默认搜索引擎合成新的 URL;如果用户输入的内容符合 URL 规则,浏览器就会根据 URL 协议,在这段内容上加上协议合成合法的 URL
2,浏览器导航栏显示 loading 状态,但是页面还是呈现前一个页面,这是因为新页面的响应数据还没有获得
3,浏览器进程通过进程间通信(IPC)把 url 请求发送给网络进程
4,网络进程接收到 url 请求后检查本地缓存是否缓存了该请求资源,如果有则将该资源返回给浏览器进程(状态码 200)
5,如果没有,网络进程向 web 服务器发起 http 请求(网络请求),请求流程如下:
- 5.1 进行 DNS 解析,获取服务器 ip 地址:如果缓存过当前域名信息,就会直接返回缓存信息;
- 5.2 根据 ip 地址和服务器建立 tcp 连接,tcp 三次握手。
- 5.2.1 传输层生成 TCP 数据包(包含源端口号、目的端口号),继续向下传输到网络层
- 5.2.2 给数据包加上 IP 头部——包括源 IP、目的 IP,继续向下传输到物理层
- 5.2.3 物理层通过物理网络(如光纤)传输给目的服务器主机
- 5.2.4 目的服务器网络层接收到数据包,解析出 IP 头部,识别出数据部分,将解开的数据包向上传输到传输层
- 5.2.5 目的服务器传输层获取到数据包,解析出 TCP 头部,识别端口
- 5.3 如果是 https 请求则还需要建立 TLS 连接。
- 5.4 构建请求头信息
- 5.5 发送请求头信息
- 5.6 服务器响应后,网络进程接收响应头和响应信息,并解析响应内容
- 5.7 数据传输完成,TCP 四次挥手断开连接。如果在 HTTP 头部加上 Connection:Keep-Alive,TCP 就一直保持连接。保持 TCP 连接可以省下下次需要建立连接的时间,提示资源加载速度
6,网络进程解析响应流程;
- 6.1 检查状态码,如果是 301/302,则需要重定向,从 Location 自动中读取地址,重新进行第 4 步,
- 6.2 如果不是重定向,首先服务器会根据 请求头中的 If-None-Match 的值来判断请求的资源是否被更新, 如果没有更新,就返回 304 状态码,相当于告诉浏览器之前的缓存还可以使用,就不返回新数据了
- 6.3 200 响应处理: 检查响应类型 Content-Type。 如果是 字节流 类型,则将该请求提交给下载管理器,该导航流程结束,不再进行后续的渲染。 如果是 text/html 则通知浏览器进程,准备渲染进程进行渲染。
7,准备渲染进程
- 7.1 浏览器进程获取到通知,根据当前页面 B 是否是从页面 A 打开的并且和页面 A 是否是同一个站点(根域名和协议一样就被认为是同一个站点)。
- 7.2 如果相同,则复用原来的进程。如果不同,新创建一个新的渲染进程
- 传输数据、更新状态
- 8.1 渲染进程准备好后,浏览器进程向渲染进程发起“提交文档”的消息,渲染进程接收到消息后,和网络进程建立传输数据的“管道”
- 8.2 渲染进程接收完数据后,向浏览器发送“确认提交”
- 8.3 浏览器进程接收到“确认提交”的消息后,更新浏览器界面状态:包括安全状态、地址栏的 URL、前进后退的历史状态,并更新 web 页面,此时的 web 页面是空白页。
- 渲染进程渲染页面
- 9.1 构建 DOM 树
- 9.1.1 输入:HTML 文档 -> 处理:HTML 解析器解析 -> 输出:DOM 数据解构
- 9.1.2 具体:接收到 Bytes 字节流->(转换)HTML 字符串->(解析)Token->(构建)Node->(合并)Dom 树
- 9.2 样式计算(构建 CSSOM 树)
- 9.2.1 输入:CSS 文本(Link 外部引入、style 标签、元素 style 属性)
- 9.2.2 处理:属性值标准化,每个节点具体样式(继承、层叠)
- 9.2.3 输出:styleSheets(CSSOM 树)
- 9.3 页面布局(构建布局树)
- 9.3.1 作用是:计算出 DOM 树中可见元素的几何位置
- 9.3.2 具体:先将 DOM 树和 CSSOM 树合并为布局树(只包含可见节点),然后进行布局计算,计算布局树节点的坐标位置。
- 9.4 分层
- 9.4.1 特定节点生成专用图层,生成一棵图层树(层叠上下文、Clip,类似 PhotoShop 里的图层);
- 9.4.2 拥有层叠上下文属性(明确定位属性、透明属性、CSS 滤镜、z-index 等)的元素会创建单独图层;
- 9.4.3 没有图层的 DOM 节点属于父节点图层;
- 9.4.4 需要剪裁的地方也会创建图层。
- 9.5 图层绘制
- 9.5.1 输入:图层树;
- 9.5.2 渲染引擎对图层树中每个图层进行绘制;
- 9.5.3 拆分成绘制指令,生成绘制列表,提交到合成线程;
- 9.5.4 输出:绘制列表。
- 9.6 分块(将图层划分为图块)
合成线程会将较大、较长的图层(一屏显示不完,大部分不在视口内)划分为图块(tile,
256*256
,512*512
)。 - 9.7 栅格化(栅格化,是指将图块转换为位图)
- 9.7.1 在栅格化线程池中,将视口附近的图块优先生成位图(栅格化执行该操作);
- 9.7.2 快速栅格化:GPU 加速,生成位图(GPU 进程)。
- 9.8 合成和显示
- 9.8.1 绘制图块命令——
DrawQuad
,提交给浏览器进程; - 9.8.2 浏览器进程的 viz 组件,接收合成线程发过来的
DrawQuad
命令,根据DrawQuad
命令,绘制在屏幕上。
- 9.8.1 绘制图块命令——
# 最后
文中若有不准确或错误的地方,欢迎指出,有兴趣可以的关注下Github~