浏览器网页请求过程
- 网络:请求资源
- 渲染:处理渲染
完整的 HTTP 请求过程
域名解析 ==> 与服务器建立连接 ==> 发起 HTTP 请求 ==> 服务器响应 HTTP 请求,浏览器得到 html 代码 ==> 浏览器解析 html 代码,并请求 html 代码中的资源(如 js、css、图片) ==> 浏览器对页面进行渲染呈现给用户
一、域名解析
- Chrome 浏览器 会首先搜索浏览器自身的 DNS 缓存,有且没有过期则解析到此结束。
- 如果浏览器自身的缓存里面没有找到对应的条目,会搜索操作系统自身的 DNS 缓存,有且没有过期则停止搜索解析到此结束
Windows 系统:
ipconfig/displaydns
命令查看
- 如果在 Windows 系统的 DNS 缓存也没有找到,则读取 hosts 文件
hosts 位于
C:\Windows\System32\drivers\etc\hosts
hosts 文件中也没有找到对应的条目,浏览器就会发起一个 DNS 的系统调用,就会向本地配置的首选 DNS 服务器发起域名解析请求
并返回给 Windows 系统内核,内核又把结果返回给浏览器。(这是递归的请求,也就是运营商的 DNS 服务器必须得提供并返回该域名的 IP 地址)
经过以上的 4 个步骤,还没有解析成功
注:一般会进行以下几步
操作系统就会查找 NetBIOS name Cache == > WINS 服务器 ==> 客户端就要进行广播查找 ==> 客户端就读取 LMHOSTS 文件
如果还没有解析成功,那么就宣告这次解析失败,那就无法跟目标计算机进行通信。只要其中有一步可以解析成功,那就可以成功和目标计算机进行通信。
二、与服务器建立连接
- TCP 连接的建立
客户端的请求到达服务器,首先就是三次握手建立 TCP 连接
三次握手的目的:试探一下对方是否遵循 TCP/IP 协议,为了在不可靠的信道上建立起可靠的连接
为什么要进行第三次握手:为了防止服务器端开启一些无用的连接,增加服务器开销;
以及防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
三、发起 HTTP 请求
http 协议:计算机通过网络进行通信的规则,是一个基于请求与响应,无状态的,应用层的协议,常基于 TCP/IP 协议传输数据。
请求报文结构
请求报文包括四个部分:请求行,请求头,空行,请求体。
四、服务器端响应 HTTP 请求,浏览器得到 HTML 代码
HTTP 的响应报文也由四部分组成:响应行、响应头、空行、响应体
五、浏览器渲染过程
- 解析 html 结构,形成 Dom 树
- 解析 CSS,生成 cssom
- 将 CSSOM 和 DOM 合并形成 render 树
- 计算 layout 布局
- 将布局渲染到屏幕上
整个渲染流程分为多个阶段,分别是: HTML 解析、样式计算、布局、分层、绘制、分块、光栅化、画
一、解析 HTML
解析过程中遇到 CSS 解析 CSS,遇到 JS执行 JS。为了提高解析效率,浏览器在开始解析前,会启动一个预解析的线程,率先下载 HTML 中的外部 CSS 文件和外部的JS 文件。
如果主线程解析到 link 位置,此时外部的CSS 文件还没有下载解析好,主线程不会等待,继续解析后续的 HTML。这是因为下载和解析 css 的工作是在预解析线程中进行的。这就是csS 不会阻塞 HTML 解析的根本原因。
如果主线程解析到 script 位置,会停止解析 HTML,转而等待 JS 文件下载好,并将全局代码解析执行完成后,才能继续解析 HTML。这是因为 Js 代码的执行过程可能会修改当前的DOM 树,所以 DOM 树的生成必须暂停。这就是 JS 会阳塞 HTML 解析的根本原因。
第一步完成后,会得到 DOM 树和 CSSOM 树,浏览器的默认样式、内部样式、外部样式、行内样式均会包含在 CSSOM 树中。
解析成对象,提供 JS 可操作的能力
二、解析 CSS
document.styleSheets、document.styleSheets[0].addRule('div':'border :2px solid red')
可查看、操作浏览器样式表
三、样式计算
主线程会遍历得到的DOM 树,依次为树中的每个节点计算出它最终的样式,称之为 Computed Style
。
在这一过程中,很多预设值会变成绝对值,比如 red 会变成 rgb;相对单位会变成绝对单位,比如 em 会变成 px
这一步完成后,会得到一棵带有样式的DOM 树
四、布局Layout
DOM树和 Layout 不一定是一一对应的,比如head
默认样式display:none
,::before
在 Layout 树阶段,布局完成后形成布局树。
五、分层Layer
主线程使用复杂的策略对布局树进行分层。
六、绘制Paint
为每个层生成绘制指令
七、分块Tiling
分块工作交给多个线程同时进行
八、光栅化Raster
合成线程将信息交给 GPU 进程,将每个快变成位图,优先处理靠近视口的块,此过程会用到 GPU 加速,提升运算速率。
九、画Draw
合成线程计算出每个位图在屏幕上的位置,交给 GPU 进行呈现。变形(旋转,缩放,倾斜)等发生在合成线程,与渲染主线程无关,这是 transform
效率高的本质原因。
回流reflow
reflow 的本质就是重新计算 layout 树。
当进行了会影响布局树的操作后,需要重新计算布局树,会引发 layout。
为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当 JS 代码全部完成后再进行统一计算。所以,改动属性造成的 ref1ow 是异步完成的。
也同样因为如此,当 JS 获取布局属性时,就可能造成无法获取到最新的布局信息浏览器在反复权衡下,最终决定获取属性立即 ref1ow。
引起回流属性和方法:任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发回流。
- 页面首次渲染
- 添加或者删除可见的DOM元素
- 元素尺寸或位置发生改变
- 元素字体大小变化
- 浏览器窗口大小发生改变
- 激活CSS伪类(例如::hover)
- 查询某些属性或调用某些方法
重绘repaint
repaint 的本质就是重新根据分层信息计算了绘制指令。 当改动了可见样式后,就需要重新计算,会引发 repaint。 由于元素的布局信息也属于可见样式,所以reflow 一定会引起 repaint。 需要更新属性,只是影响元素的外观、风格,不影响布局。(不影响布局的属性,如:color、background-color、visibility 等)
为什么 transform 的效率高?
因为 transform 既不会影响布局也不会影响绘制指令,它影响的只是渲染流程的最后一个「draw」 阶段由于 draw 阶段在合成线程中;
所以 transform 的变化几乎不会影响渲染主线程。反之,渲染主线程无论如何忙碌.也不会影响 transform 的变化。
六、浏览器对页面进行渲染呈现给用户,关闭连接
四次挥手
问题一:
为什么连接的时候是三次握手,关闭的时候却是四次握手?
为了保障数据发送完再断开连接
问题二:
为什么要等待一段时间在关闭连接?
因为客户端发送完 ack 包后中途可能丢失,此时服务端未收到 ack 包会重发 fin 包,客户端在发送 ack 包刷新等待时间,
确保服务端关闭再 关闭客户端