目录
3.2 发送 HTTP 请求,并接收服务器响应结果,关闭 HTTP 连接
一、总体流程
从浏览器访问url,到页面别成功渲染,大致流程如下:
- DNS解析
- 浏览器与目标服务器建立TCP连接
- 发送HTTP请求
- 服务器处理请求,并返回响应报文,断开TCP连接
- 浏览器解析和渲染页面
二、DNS 域名解析
DNS 域名解析其实就是寻找存储了想要获取的资源的那一台服务器 IP 地址的过程。当你在浏览器中输入了一个地址,如:
www.baicu.com,这其实并不是真正的服务器地址,而是通过这个域名向 DNS 服务器查询到这个域名真正指向的 IP 地址。
2.1 DNS 域名解析的过程
- 客户端收到输入的域名后,先在本地 host 中查找域名对应的 IP 关系,若找到了,则直接向对应的 IP 建立连接,获取资源等。 若没有找到,则向 DNS 服务器发送这个域名,请求服务器解析。
- 客户端输入域名
- 在本地 host 中查找域名对应的 IP 关系,若找到了,直接跳过域名解析过程,继续2.2步骤
- 若本地 host 中没有域名对应关系,则向本地 DNS 服务器发送一个含有域名 www.cnblogs.com 的 DNS 查询报文
- 本地服务器发送域名到跟DNS服务器,根服务器注意到 com 后缀,向本地 DNS 服务器返回 comDNS 服务器的地址
- 本地服务器再次向 comDNS服务器发送查询请求,comDNS 服务器注意到其 www.cnblogs.com 后缀并返回负责该域名的权威DNS服务器的IP地址
- 本地服务器向权威 DNS 服务器请求资源,并接收响应
三、建立TCP连接,发送Http请求资源
3.1 建立 TCP 连接
客户端成功拿到服务器地址后,与服务器建立 TCP 连接。
客户端发送一个带有SYN标志的数据包给服务端,服务端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息,最后客户端再回传一个带ACK标志的数据包,代表握手结束,连接成功。
上图也可以这么理解:
客户端:“你好,在家不,有你快递。”
服务端:“在的,送来就行。”
客户端:“好嘞。”
3.2 发送 HTTP 请求,并接收服务器响应结果,关闭 HTTP 连接
客户端向服务器发送 get 或 post 请求,获取资源信息,并接收服务器返回的响应报文。每一个 get 或 post 请求都是一个Http连接,都要经历 建立连接 => 请求 => 响应 => 断开连接 这四个过程。
四、浏览器解析HTML
4.1 浏览器解析过程
浏览器是一个边解析边渲染的过程。过程如下:
- 浏览器解析HTML文件构建DOM树,
- 解析CSS文件构建渲染树
- 渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上
五、回流(Reflow)和 重绘(Repaint)
在讨论回流与重绘之前,我们要知道:
- 浏览器使用流式布局模型 (Flow Based Layout)。
- 浏览器会把
HTML
解析成DOM
,把CSS
解析成CSSOM
,DOM
和CSSOM
合并就产生了Render Tree
。 - 有了
RenderTree
,我们就知道了所有节点的样式,然后计算他们在页面上的大小和位置,最后把节点绘制到页面上。 - 由于浏览器使用流式布局,对
Render Tree
的计算通常只需要遍历一次就可以完成,但table
及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table
布局的原因之一。 - 回流必将引起重绘,重绘不一定会引起回流。
5.1 回流
当Render Tree
中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。
会导致回流的操作:
- 页面首次渲染
- 浏览器窗口大小发生改变
- 元素尺寸或位置发生改变
- 元素内容变化(文字数量或图片大小等等)
- 元素字体大小变化
- 添加或者删除可见的
DOM
元素 - 激活
CSS
伪类(例如::hover
) - 查询某些属性或调用某些方法
一些常用且会导致回流的属性和方法:
clientWidth
、clientHeight
、clientTop
、clientLeft
offsetWidth
、offsetHeight
、offsetTop
、offsetLeft
scrollWidth
、scrollHeight
、scrollTop
、scrollLeft
scrollIntoView()
、scrollIntoViewIfNeeded()
getComputedStyle()
getBoundingClientRect()
scrollTo()
5.2 重绘
当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color
、background-color
、visibility
等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
5.3 性能影响
回流代价比重绘代价大。
有时候一个元素回流,会导致他的父元素和他相关的元素也回流。
5.4 回流优化
现代浏览器会对频繁的回流或重绘进行优化
即浏览器会维护一个队列,将所有要回流和重绘的操作放入队列中,当队列满了或是达到时间阈值后会清理一次队列,进行一次批处理,这样可以把多次回流和重绘变成一次。
当你访问以下属性或方法时,浏览器会立刻清空队列:
-
clientWidth
、clientHeight
、clientTop
、clientLeft
-
offsetWidth
、offsetHeight
、offsetTop
、offsetLeft
-
scrollWidth
、scrollHeight
、scrollTop
、scrollLeft
-
width
、height
-
getComputedStyle()
-
getBoundingClientRect()
因为队列中可能存在影响了这些属性和方法返回值的操作,浏览器为了确保你拿到的数据是最准确的,会先强制清理队列,进行一次批处理。
5.5 如何避免
5.5.1 CSS
- 避免使用 table
- 尽可能在dom树的末端修改class
- 避免设置多层内联样式
- 避免使用CSS表达式(如calc)
- 尽量将动画效果应用到 position 为 absolute 和 fix 的节点上
5.5.2 JavaScript
- 避免频繁操作样式,最好一次性重写 style 属性,或将样式列表定义在一个class里,并一次性更改
- 避免频繁操作dom,可以创建一个documentFragment,在它上面应用所有dom操作,最后将它添加到文档中
- 先为元素设置 display: none,操作结束后再将他显示出来。因为在
display
属性为none
的元素上进行的DOM
操作不会引发回流和重绘。 - 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
- 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
参考链接: