浏览器从输入网址到页面显示的过程
浏览器主进程解析地址栏中的内容,如果是地址正确拼接协议;如果是搜索内容,拼接搜索地址。
将请求地址交给浏览器网络进程,构建请求行
查找是否存在缓存,有则直接返回缓存
通过
DNS
域名解析得到IP
地址查找顺序为:
- 查找浏览器缓存,有缓存则返回
IP
- 查找本机缓存,有缓存则返回
IP
- 查找本机配置
DNS
服务器,有缓存则返回IP
,无则由本机配置DNS
服务器向根域名服务器中查找 - 根域名服务器会返回顶级域名服务器(.com 等)地址
- 本机配置
DNS
服务器再向顶级域名服务器查找,会返回权威域名服务器地址 - 本机配置
DNS
服务器再向权威域名服务器地址查找,找到后返回IP
(由域名服务商提供,能正确找到IP
)
- 查找浏览器缓存,有缓存则返回
如果请求地址中没有端口号,使用默认端口号
80
(HTTP
)或443
(HTTPS
)通过三次握手建立
TCP
连接(同一域名最多同时存在 6 个连接,如果已满需要等待)- 第一次握手:客户端发送
SYN
报文并设置序列号为A
,表示能够发送 - 第二次握手:服务端回复
ACK
报文并设置序列号为A+1
,以及SYN
报文并设置序列号 B,表示能够接收和发送 - 第三次握手:客户端回复
ACK
报文并设置序列号为B+1
,表示能够接收
- 第一次握手:客户端发送
发送
HTTP
请求服务端处理并返回
HTTP
响应,如果响应为重定向,从步骤 2 开始请求新地址;如果响应Content-Type
为二进制流类型,浏览器尝试下载,否则尝试解析展示TCP 单次传输的数据包通常在 14KB,HTTP 响应会被拆分为多个数据包,在传输完成后进行排序、组合
如果请求头未包含
Connection: Keep-Alive
,则通过四次挥手断开TCP
连接- 第一次挥手:发起断开方发送
FIN
报文并设置序列号为A
,表示自己没有要发送的内容了 - 第二次挥手:接收断开方发送
ACK
报文并设置序列号为A+1
,表示收到断开请求,等我检查是否还需要发送 - 第三次挥手:接收断开方发送
FIN
报文并设置序列号为B
,表示自己没有要发送的内容了 - 第四次挥手:发起断开方发送
ACK
报文并设置序列号为B+1
,表示确认断开。此时接收断开方收到后便断开连接,而发起断开方需要等到一段时间确认报文发送成功后再断开。
- 第一次挥手:发起断开方发送
浏览器主进程新开一个渲染进程(如果是从协议和根域名相同的页面中打开的,会复用同一个渲染进程)
浏览器主进程向渲染进程发送“提交文档”消息,渲染进程与网络进程通信并获取响应;待渲染进程接收响应完毕后向主进程发送“确认提交”消息,主进程更新浏览器界面状态
(如果响应是
HTML
代码)HTML 解析器
模块开始解析代码(边加载边解析)并构建DOM
树- 渲染引擎收到
HTML
代码字节流后,会开启一个预解析线程,用来分析代码中存在的JS
和CSS
链接,并提前加载这些文件。所以浏览器网络请求中,HTML
、JS
、CSS
的优先级高于图片等静态资源 HTML 解析器
会首先对HTML
代码进行分词,然后从根节点开始使用栈结构的方式构建DOM
树。栈底为全局Document
对象,然后每一个开始标签进行入栈,当结束标签入栈时会匹配对应的开始标签,匹配成功后表示这段代码解析完成,便会取出加入DOM
树对象中;文本块不需要入栈,直接加入DOM
树对象- 当解析到没有
async
或defer
属性的script
块时,HTML 解析器
会暂停解析并开始加载执行脚本代码。因为JS
中也有可能操作CSS
,所以在这之前还会等待CSS
的加载和解析。脚本加载之后会将代码作为宏任务放入消息队列等待执行 - 解析到带有
async
属性的script
块时,不会暂停HTML
解析,而是异步加载脚本。等脚本加载完成后再暂停HTML
解析,并以普通script
块同样的方式进行处理 - 解析到带有
defer
属性的script
块时,不会暂停HTML
解析,而是异步加载脚本。等DOM
树构建完成后(DOMContentLoaded
事件触发后)再以普通script
块同样的方式进行处理 - 当解析到其他资源时,会异步请求资源,不会阻塞
HTML
解析和页面渲染(图片等元素异步请求完成后会产生新的合并Render
树、布局计算、分层、渲染事件,并加入事件循环中)
- 渲染引擎收到
将从不同来源解析得到的
CSS
代码(样式表与内联样式)构建为CSSOM
树从
DOM
树中复制元素到Render
树,这个过程会过滤掉不需要显示的元素。之后将CSSOM
树中的样式应用到Render
树的每一个元素(CSS
中使用的图片,会在这时才开始加载)渲染引擎计算
Render
树中每一个元素的显示几何位置,之后在合适的时机开始渲染流程(例如一个宏任务执行结束后)渲染流程是在合成线程中进行的,所以不会阻塞主线程
对渲染树中的元素进行分层,形成图层树
支持
GPU
硬件加速的元素包括:- 具有 3D 变换属性的元素,如使用
transform
- 使用硬件加速的元素,如使用
will-change
- 使用透明度属性
opacity
的元素 - 使用滤镜属性的元素,如混合模式(
mix-blend-mode
)、CSS 过滤器(filter
)和遮罩(mask
) - 具有动画(
animation
)和过渡(transition
)效果的元素 - 具有固定定位(
fixed
)或黏性定位(sticky
)的元素 - 被裁剪的元素,如具有滚动条或使用了
clip-path
。 video
、canvas
、webGL
等特定媒体元素
这些元素会使用单独的图层,自身修改不会触发其他图层的重排与重绘操作,所以性能更高。
通常所说的
CSS
动画性能高于JS
动画是因为:JS
动画需要手动控制绘制频率,绘制操作存在于主线程中,可能被其他任务阻塞;而CSS
动画由浏览器自己管理,能保持更好的流畅性JS
动画元素如果未单独分层,绘制会与其他元素一同计算,导致部分性能上的损失
- 具有 3D 变换属性的元素,如使用
遍历图层树,生成每个图层的绘制指令
对页面进行栅格化(分块),并优先绘制视口附近的块,之后合并每一块的图像
将图像显示到屏幕上