页面输入URL之后发生了什么
浏览器输入 URL 按下回车之后,浏览器会经历一系列复杂的步骤来获取并展示网页内容...
一、URL 解析与预处理
首先进行补全协议,如果 URL 未明确协议,浏览器会自动补全,通常默认使用 https://
接下来拆分 URL 结构,如协议、域名、端口、路径、查询参数、锚点
二、域名解析 DNS
将域名(如 myNet.com
)转换为服务器的 IP 地址(如 93.184.213.34
)
首先检查浏览器自身的 DNS 缓存,若存在缓存,直接使用 IP 地址,调过后续 DNS 查询
若浏览器缓存中无记录,操作系统会查询本地 DNS 缓存
若本地缓存均无记录,浏览器会向本地 DNS 服务器发起查询,通常先进行自身缓存查询,在逐层向上级 DNS 服务器请求解析。DNS 查询可能耗时数十毫秒到数秒,是影响网页加载速度的关键因素之一
三、建立网络连接 TCP
- TCP 三次握手
1、浏览器发送一个 SYN 包,请求建立连接
2、服务器返回 SYN-ACK 包,请求确认并同步序列号
3、浏览器发送 ACK 包,完成链接建立
- TLS/SSL 握手
1、浏览器发送客户端支持的加密算法列表
2、服务器选择加密算法,返回证书(包含公钥)
3、浏览器验证服务器证书有效性(检查颁发者,有效期,域名是否匹配)
4、浏览器生成随机秘钥,用服务器公钥加密后发送给服务器
5、服务器用私钥解密,获取随机密钥,双方通过该秘钥加密通信内容
四、发送请求 HTTP/HTTPS
建立连接后,浏览器向服务器发送 HTTP/HTTPS 请求 get/post
五、服务器处理请求并返回响应
服务器解析请求方法、路径和参数,确定需要返回的资源(HTML,CSS,JS,图片等)
若为静态资源,直接读取文件,若为动态资源,须通过后端处理生成响应内容,就是平时的接口返回数据
六、浏览器解析与渲染页面
浏览器的网络线程会发送 HTTP 请求,和服务器之间进行通信,之后将拿到的 HTML 封装成一个渲染任务,并将其传递给渲染主线程的消息队列,在时间循环机制的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程。
-
HTML 解析
解析 html 字节数据->字符串->字符串标记->分析 DOM 节点->构建 DOM 节点树
解析 html 的过程会遇到 style、link 标签,为了提高解析效率,浏览器在开始解析钱,会启动一个预解析的线程,率先下载 HTML 中的外部 css 文件。
解析的过程中遇到 script 时,会停止解析 HTML ,转而等待 JS 文件下载好,并将全局代码解析执行完成后,才能继续解析 HTML。因为 JS 代码的执行过程中可能会修改当前的 DOM 树,所以 DOM 树的生成必须暂停。
因此想首屏渲染的越快,建议将 script 标签放在 body 标签底部。但是在现代浏览器中,有新的方式来避免 JS 代码阻塞渲染。async、defer、prefetch、preload 这步最终得到 DOM 树和 CSSOM 树,浏览器的默认样式、内部样式、外部样式、行内样式包含在 CSSOM 树中。 -
样式计算
依次为树中的每个节点计算出它最终的样式,DOM 树和 CSSOM 树合并为一颗带有样式的 DOM 树 -
布局
主线程遍历刚刚构建的 DOM 树,根据节点的计算样式计算出一个布局树,描述了每个节点的 x, y 坐标以及盒子大小。 -
分层
主线程遍历布局树创建层次树,分层的好处在于将来某一个层改变后,仅会对盖层进行后续处理,从而提升效率。 -
生成绘制指令
主线程会为每个层单独产生绘制指令集,用于描述这一层的内容该如何画出来。生成绘制指令集后,渲染主线程的工程就暂时告一段落,接下来主线程将每个图层的绘制信息提交给合成线程,剩余工作将由合成线程完成 -
分块
合成线程首先对每个图层进行分块,将其划分为更多的小区域。 -
光栅化
分块完成后,进入光栅化阶段。所谓光栅化,就是将每个块变成位图。 -
绘制
当所有的图块都被栅格化后,合成线程会拿到每个层、每个块的位图,从而生成一个个「指引(quad)」信息
question
什么是 reflow
reflow 的本质就是重新计算 layout 树。
当进行了会影响布局树的操作后,需要重新计算布局树,会引发 layout。
为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 reflow 是异步完成的。
也同样因为如此,当 JS 获取布局属性时,就可能造成无法获取到最新的布局信息。
浏览器在反复权衡下,最终决定获取属性立即 reflow。