- 凡是涉及到性能优化相关的话题,必定和浏览器相关,因此我们先从浏览器的最基础入手来查看
一、在浏览器中输入URL到页面渲染的整个过程
1、输入URL按下回车
1、应用层进行DNS解析:通过DNS解析将域名解析成IP地址,在解析的过程中按照浏览器缓存、系统缓存、路由缓存、DNS缓存、根域名服务器、顶级域名服务器、主域名服务器的顺序,逐步读取缓存。直到拿到IP地址
2、应用层生成HTTP请求报文
3、传输层建立TCP连接:传输层的传输协议分为UDP(用户数据协议)和TCP(传输控制协议)两种
4、网路层使用IP协议来选择线路(路由)
5、数据链路层实现网络相邻结点间可靠的数据通信
6、物理层传输数据
汇总: DNS解析URL地址、生成HTTP请求报文、构建TCP连接、使用IP协议选择传输路线、数据链路层保证数据的可靠传输、物理层传输数据
2、浏览器渲染网页的具体流程
1、构建DOM树: 当浏览器接收到服务器响应来的HTML文档后,会遍历文档节点,生成DOM树
注意:
- DOM树在构建的过程中可能会被CSS和JS加载而阻塞
- display:none的元素也会在DOM树中
- 注视也会在DOM树中
- script标签也会在DOM树中
- 无论是DOM还是CSSOM,都是要经过Bytes→characters→tokens→nodes→objectmodel这个过程
2、构建CSSOM树: 浏览器解析CSS文件生成CSSOM,每个CSS文件都被解析成一个StyleSheet对象,每个对象都包含CSS规则,CSS规则对象包含对应CSS语法的选择器和声明对象以及其他对象
注意:
- CSS解析可以与DOM解析同时进行
- CSS解析与script的执行互斥
- 在Webkit内核中进行了script执行优化,只有在JS访问CSS时才会发生互斥。
3、构建渲染树(RenDer Tree):通过DOM树和CSS规则树来构建渲染树。浏览器会从DOM树的根节点开始便利每个可见的节点,然后对每个可见的节点找到适配的CSS样式规则并应用
注意:
- Render Tree 和 DOM Tree并不完全对应
- display:none的元素不再Render Tree中
- visibility:hidden元素在Render Tree中
4、渲染树布局(Layout):布局阶段会从渲染树的根节点开始遍历,由于渲染树的每一个节点都是一个Render Object对象,包含宽高、位置、背景等信息。所以浏览器可以通过这些样式信息来确定每个节点对象在页面的准确位置和大小。布局阶段的输出就是我们常说的盒模型。
注意:
- 我们长说的脱离文档流其实就是脱离Render Tree
5、渲染树绘制(Painting):在绘制阶段,浏览器会遍历渲染树,调用渲染器的paint()方法在屏幕上显示其内容
3、回流和重绘(reflow和repaint)
HTML默认是流式布局,但是CSS和JS会打破这种布局.
1、回流: 对DOM的修改引发DOM尺寸的变化(比如宽高、隐藏元素等),浏览器会重新计算元素的几何属性.然后在将计算的结果绘制出来,这个过程就是回流
2、 重绘: 当我们对DOM修改导致样式发生改变(颜色等),但并未影响几何属性时,浏览器不需要重新计算元素的几何属性,直接为元素绘制新的样式.跳过回流环节
3、减少回流的次数
用transform做形变和位移可以减少reflow。
避免逐个修改节点样式,尽量一次性修改。
使用DocumentFragment将需要多次修改的DOM元素缓存,最后一次性append到真实DOM中渲染
4、为什么操作DOM慢
用JS去操作DOM时,本质上是JS引擎和渲染引擎之间进行了"跨界交流",它依赖桥接接口作为桥梁,我们每操作一次DOM过桥的次数就多一次,就会产生比较明显的性能问题。因此减少DOM操作
二、动画为什么会卡顿?
浏览器有2个重要的执行线程,这2个线程协同工作来渲染一个网页分别是:主线程和合成线程,
一般情况下主线程负责执行JavaScript(执行JS是单线程执行)计算HTML元素CSS样式,页面布局,将元素绘制到一个或者多个位图中,然后将这些位图交给合成线程。
合成线程负责通过GPU将位图绘制到屏幕上
而造成页面卡顿的原因就是主线程和合成线程调度不合理造成的,例如在使用height,width,margin,padding作为transition的值时,会造成浏览器主线程的工作量较重(因为每移动一像素就需要回流一次),因为每次样式的更改主线程都需要经历执行:JS、Render Tree、Layou、 paint四个阶段。而当我们使用transform的时候主线成一次就可以完成相对应的工作。所以在做CSS3动画的时候优先推荐:transform,transform 和 opacity 实现动画能够让节点被放置到一个独立合成层中进行渲染绘制,动画不会影响其他图层,并且 GPU 渲染相比 CPU 能够更快,这会让你的动画变的更加流畅
三、合成层
一般来说拥有特定属性的渲染层会被浏览器自动提升提升为合成层,合成层拥有单独的图层,和其他图层之间互不影响。而其它不是合成层的渲染层,则和第一个拥有图层的父层共用一个,也就是普通文档流中的内容,我们看一些常见的提升为合成层的属性
- transform: translateZ(0)
- backface-visibility: hidden
- will-change
- video、canvas、iframe等元素
合成层的利弊
优点:
- 开启硬件加速,合成层的位图会交由 GPU 合成,相比 CPU 处理要快。
- 合成层发生 repaint 的时候,不会影响其他图层。
- 对于 transform 和 opacity 效果,不会触发 layout 和 paint
缺点:
- 任何带有 position: fixed 或者 position: absolute 的子元素将会相对于设置了 will-change: transform 的元素进行相对定位
- will-change会耗费更多的资源,滥用会造成页面响应速度变慢或者崩溃
\