1. 提高页面加载速度
具体方式请参考博主文章:提高页面加载速度
2.回流(reflow)与重绘(repaint)
先看下两者概念:
回流(reflow):也叫重排,指的是重新计算页面布局,一个元素的回流导致了其所有子元素以及DOM中紧随其后的祖先元素的随后的回流。大部分的回流将导致页面重新渲染。
重绘(repaint):即重新绘制,它不会影响布局,只会影响元素的外观、风格等。
回流必然导致重绘,重绘不一定导致回流。
有个大致印象,我们来详细看看网页的生成过程:
浏览器取回代码后,首先要做两件事:Html转化为DOM+css样式解析CSSOM(css object model) ,然后结合DOM、CSSOM生成一个渲染树(Render Tree),display:none的元素不会被渲染进来,一旦渲染完成就将渲染树所有节点平面合成,生成布局(Layout/flow),最后将布局绘制在屏幕上。
DOM+CSSOM => Render Tree => Layout /Flow=> Paint
上面步骤最耗时的就是flow,paint,可看出网页生成的时候至少会渲染(flow+paint)一次,而后期一些操作还会导致重新渲染,这就是我们上面所说的,reflow和repaint了,他们非常耗费资源,从而导致网页性能低下。
导致reflow的原因常见的有:
调整窗口大小
改变字体
增加或者移除样式表
内容变化,比如input框中输入文字
激活CSS伪类
操作CSS属性
JavaScript操作DOM
计算offsetWidth和offsetHeight
设置style属性的值
如何操作才能使回流尽可能减少?
1. 如果想设定元素的样式,通过改变元素的 class 名来实现.
我们都知道与DOM交互很慢。避免设置多级内联样式,因为每个都会造成回流,样式可以合并在一个外部类,这样当该元素的class属性可被操控时仅会产生一个reflow。
//不推荐
el.style.left = "20px";
el.style.top = "15px";
// 推荐
el.className += " new_class";
2.
应用元素的动画,使用 position 属性的 fixed 值或 absolute 值
动画效果应用到position属性为absolute或fixed的元素上,它们不影响其他元素的布局,所它他们只会导致重新绘制,而不是一个完整回流。这样消耗会更低。
3. 避免使用table布局
即使一些小的变化将导致表格(table)中的所有其他节点回流。
4. 如果某个样式是通过重排得到的,那么最好缓存结果。避免下一次用到的时候,浏览器又要重排。
样式写操作后,读取offsetTop/Left/Width/Height, scrollTop/Left/Width/Height,clientTop/Left/Width/Height,都会引发浏览器立即重新渲染,可以将他们先保存到变量中,用到时候直接取变量
//不推荐
div.style.left = div.offsetLeft + 10 + "px";
div.style.top = div.offsetTop + 10 + "px";
// 推荐
var offLeft = div.offsetLeft;
var offTop = div.offsetTop;
div.style.left = offLeft + 10 + "px";
div.style.top = offTop + 10 + "px";
5. 减少不必要的 DOM 层级(DOM depth)。
改变 DOM 树中的一级会导致所有层级的改变,上至根部,下至被改变节点的子节点。这导致大量时间耗费在执行 reflow 上面。
6. 牺牲平滑度换取速度
Opera还建议我们牺牲平滑度换取速度,其意思是指您可能想每次1像素移动一个动画,但是如果此动画及随后的回流使用了100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流做斗争。动画元素每次移动3像素可能在非常快的机器上看起来平滑度低了,但它不会导致CPU在较慢的机器和移动设备中抖动。
7. 不要过多的频繁的去增加,修改,删除元素.
这可能会频繁的导致页面reflow,可以先把该dom节点抽离到内存中进行复杂的操作然后再display到页面上。
8. 虚拟DOM,比如React,Vue2.0
当页面状态发生变化而需要操作DOM时,我们可以先通过虚拟DOM计算出对真实DOM的最小修改量,然后再修改真实DOM结构(因为真实DOM的操作代价太大)。
更多详见阮大大:http://www.ruanyifeng.com/blog/2015/09/web-page-performance-in-depth.html