(一)层层突破之回流重绘
层层突破
回流重绘、跨域、浏览器相关考点是成为一个前端切图仔必不可少的基础知识了吧,从这篇文章开始一一搞定它们!
一、从输入url到页面渲染发生了什么?
在聊这个回流重绘之前,我们首先要知道浏览器从输入url到页面渲染发生了什么呢? 它主要分为两大步:
1. 第一大步
(1)DNS解析
DNS是用来解析域名的分布式数据库系统,将域名解析为IP地址。DNS分为两种查询方式,迭代查询(靠自己)和递归查询(靠别人),这里介绍DNS的迭代查询。 它的步骤是:客户端->本地域名服务器->根域名服务器->顶级域名服务器->目标服务器。 解析过程如下:

(2)HTTP建立连接
连接传输的过程分为连接建立(TCP三次握手),数据传送,连接释放(TCP四次挥手)。
1) 连接建立(TCP三次握手)
整个过程就像这两位的对话:

假设运行在一台主机(客户)上的一个进程想与另一台主机(服务器)上的一个进程建立一条连接,客户应用进程首先通知客户TCP,他想建立一个与服务器上某个进程之间的连接,客户中的TCP会用以下步骤与服务器中的TCP建立一条TCP连接: · ROUND 1: 客户端发送
连接请求报文段。 SYN=1,seq=x(随机) · ROUND 2: 服务器端为该TCP连接分配缓存和变量,并向客户端返回确认报文段,允许连接。 SYN=1,ACK=1,seq=y(随机),ack=x+1 · ROUND3: 客户端为该TCP连接分配缓存和变量,并向服务器端返回确认的确认,可以携带数据。 SYN=0,ACK=1,seq=x+1,ack=y+1

2) 连接释放(TCP四次挥手)
整个过程就像这两位的对话:

参与一条TCP连接的两个进程中的任何一个都能终止该连接,连接结束后,主机中的"资源"(缓存和变量)将被释放。步骤如下: · ROUND 1: 客户端发送
连接释放报文段,停止发送数据,主动关闭TCP连接。 FIN=1,seq=u · ROUND 2: 服务器端回送一个确认报文段,客户到服务器这个方向的连接就释放了(半关闭状态)。 ACK=1,seq=v,ack=u+1 · ROUND 3: 服务器端发完数据,就发出连接释放报文段,主动关闭TCP连接。 FIN=1,ACK=1,seq=w,ack=u+1 · ROUND 4: 客户端回送一个确认报文段,再等到时间等待计时器设置的2MSL(最长报文段寿命)后,连接彻底关闭。 ACK=1,seq=u+1,ack=w+1

2. 第二大步
(1) 浏览器加载HTML代码,将其解析成DOM树
(2) 加载css代码,将其解析成CSSOM树
(3) DOM Tree + CSSOM Tree =render Tree
(4) 计算布局,render树中的每一个节点都计算一遍(回流)
(5) GPU 绘制 一个又一个的图层(重绘)
二、回流重绘
好的,咱们回归主题,回流与重绘的概念我们已经知道了,那么什么时候会触发回流,什么时候会触发重绘呢?
1. 触发回流的操作
(1) 视窗大小变化
(2) DOM集合属性发生变化
(3) 添加或者删除DOM
(4)offsetWidth,offsetHeight,offset...,clientWidth,clientHeight... ,client...,scrollTop,scroll...
回流需要更新渲染树,性能开销大,所以我们要减少回流主要有以下几种方式:
-
元素脱离文档流
-
改变样式
-
回归文档流
2. 触发重绘的操作
元素的非几何属性变化时会发生重绘,不会刷新页面
(1) color
(2) background
(3) border-radius
(4) box-shadow
(5) 背景图
回流一定重绘,重绘不一定回流
3. 浏览器的渲染队列
- 浏览器维护了一个渲染队列,当我们修改了元素的几何属性,导致浏览器发生回流和重绘时,浏览器会将该操作存进
队列,等待队列中的内存达到一定的阈值,或者到了一定的时间时,浏览器会一次性批量操作。
4. 强制刷新队列
offsetWidth,offsetHeight,clientWidth,clientHeight,scrollTop,..... 有关的操作会强制刷新渲染队列,即会触发回流。
5.优化
- 当一个dom节点
display:none时,它便不参加render树的构建 - 页面添加结构时,使用
虚拟文档片段 - 使用
克隆元素
例:我们要在ul中添加5个li,三种优化方式的代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app">
<ul id="ul"></ul>
</div>
<script>
//1.
//for循环中一次回流,render树构建一次
// let ul = document.getElementById('ul')
// ul.style.display = 'none'
// for (let i = 1; i < 5; i++) {
// let li = document.createElement('li')
// li.innerText = i
// ul.appendChild(li)
// }
// ul.style.display = 'block'
//2.
//for循环中一次回流,render树构建一次
// let ul=document.getElementById('ul')
// let frg=document.createDocumentFragment() //虚拟文档片段
// for (let i = 1; i < 5; i++) {
// let li = document.createElement('li')
// li.innerText = i
// frg.appendChild(li)
// }
// ul.appendChild(frg)
//3.
let ul = document.getElementById('ul')
let clone=ul.cloneNode(true)
for (let i = 1; i < 5; i++) {
let li = document.createElement('li')
li.innerText = i
clone.appendChild(li)
}
ul.parentNode.replaceChild(clone,ul)
</script>
</body>
</html>
转载自:https://juejin.cn/post/7251895470548385847