willchange 优化性能的原理是什么

写在前面

今天说一下性能优化部分的其中一个点,这个点叫做 willchange,说他的原因主要有以下几个:第一很多人知道用这个可以提高性能但是不知道原因是什么,第二,我们用的时候他虽然可以提高性能,但是不代表就可以肆意的使用,第三,讲一下他的工作原理是什么,下面我尽可能的说明白这三件事

什么是 willchange

willchange 可以先大概看一下 MDN 的解释,首先他是一个 css 的属性值,大概的意思就是设置了这个属性之后的元素之后相当于提前告诉浏览器你这块后面可能要做的事情,比如你要反转,移动,透明度改变等等,当然你如果不确定你后面可能要做的变化,你可以直接写上 auto,这个时候意思就是让浏览器自己想后面我们可能会做的操作,这个就是浏览器自己想办法预测你的变化,不过比较好的情况是你使用之前最好是之后你后面想要做什么事情,这样浏览器可以针对你的提前告知进行对应准确的准备,这个就是 wilchaneg 大概做的一件事。

当我们给一个块盒添加了 willchange 属性之后,浏览器做了什么

上面那段话已经说了,当设置willchange 之后,相当于我们提前告知了浏览器我们后面可能要做的事情,那么浏览器知道了之后他怎么准备呢?他首先是将你设置 willchange 属性的元素单独列了一层,那么这层独立出来之后,你后面的操作就相当于和别的元素没有任何关联,他单独处理这一块,而且是单独使用 GPU 加速处理,这里GPU 加速可以理解为一个比 CPU渲染能力更强更快的处理方式,但是因为 GPU 能做的事情比较有限,一般都是和显示相关的,所以他的性能更强,因为做的事情比较单一。

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div class="shouLayout" style="background-color: aqua;">1</div>
		<div class="shouLayout" style="background-color:#f40">3</div>
		<div class="shouLayout" style="background-color: aquamarine;">4</div>
		<div class="shouLayout" style="background-color: black;">5</div>
		<div class="shouLayout" style="background-color: brown;">6</div>
		<div class="shouLayout" style="background-color: chartreuse;">7</div>
		<div class="shouLayout" style="background-color: cornflowerblue;">8</div>
		<div class="shouLayout" style="background-color: darkblue;">9</div>
		<div class="shouLayout" style="background-color: darkgreen;">10</div>
	</body>
	<style>
		.shouLayout {
			will-change: transform;
		}
	</style>
</html>

为什么添加了层之后就可以提高性能(浏览器是怎么高性能的渲染一个页面的)

这里就要简单的说一下浏览器渲染的过程了,早期的浏览器是将一个页面平铺到画面中,拿到 html 代码之后,(这里不做 js 解析过程的说明)通过样式代理也就是浏览器自己的预处理样式、用户自己定义的样式,按照样式优先级做了计算之后得到最终的计算样式结果,也就是最终的样式列表,按照样式进行绘制画面,绘制的过程可以参考 canvas,因为 canvas 也是通过调用了浏览器本身的绘制功能工作的,最后绘制结果展示给用户,这个就是浏览器渲染的一个过程,当然真正的是远比我描述的复杂的多的,只是这里只是讲解一下 willchange 提高性能的原因说明一下,前面说了他如果都是平铺的,那么我们改动其中一个元素的几何位置的时候,也就是改变他的坐标,绘制也是通过坐标进行的,坐标加上像素点绘制的,改动其中元素位置的时候会导致 reflow 也就是重新排版,继而后面继续重新绘制,repaint,这个是很消耗性能的,整个页面完成渲染本身就很复杂,其中一个小改动还导致这么多的重排操作,就会导致页面很不流畅,后面浏览器为了解决这个问题,想到一个比较巧妙的解决方案,将页面按照层级分层,经常不动的,一个层,经常改动的一个层,这样经常改动的层改变的时候就只会影响他自己那个层,不会影响不动的那个层,这样就大大的减少了重排元素的数量,同时每一个单独的层都会使用独立的 GPU 加速处理,看到这里也许你们就可以明白为什么 willchange 可以提高性能了,因为他独立出来了一个层,符合了浏览器性能优化的一个点

分析一个例子

window12 最近比较火的一个演示界面,使用 html 实现的,我们可以简单的看一下

  • 首先他的基础页面分层就比较严重
  • 当我们打开一个控件的时候分层就更严重了
  • 可以看到他是分了很多层在做不同的事情,但是并没有使用任何的优化方式,仅仅是使用 z-index 将不同的控件放到不同的 z 轴上

  • 我们看一眼他的源码
  • 可以很清楚的看到,当我们切换不同的层级的时候,他其实就是在变化不同的 div 的一个 z 轴排列情况,当然处理方式各异,只是这样的话会导致肉眼可见的一些卡顿罢了。因为这个的特殊性,很少有需求会在浏览器中模拟一个操作系统哪怕是界面,毕竟操作系统本身是一个极其复杂的软件,浏览器本身做的事情就是相对有限的,这种操作交互极其多的情况,即使优化之后也难免会出现卡顿!

怎么合理的使用

这里可能有人会说,那我直接所有的元素都添加上 willchange 是不是就性能无敌了,当然不是,我们可以看一下 CSDN 主页的分层情况

我们可以清晰的看到,CSDN 的官方网站首页也就是三个层而已,一个是滚动条,一个是工具栏,一个就是 content,为什么他没有将模块挨个分一下呢?因为每新加一个 GPU都是对浏览器性能的消耗,所以他提高性能的同时也是对性能的一种消耗,所以最好的是找到这中间的一种平衡,而不是无脑的倾向某一个方向!

写到后面

相信写到这里大家对这个属性有了一定的了解,也知道后面怎么合理的使用了,这里多说一句,浏览器的图层分析是默认不显示的,大家可以自己点击浏览器后面的工具里面的更多选择调试出来即可!喜欢的可以关注一下,拜拜!!!