继上篇文章中 js加载执行优化现在我们聊一下对于切片仔来说听得最多的两个词语:重绘,回流。在阐述这之前我们需要知道这么几点:
-
1:css加载不会阻塞DOM树的解析
-
2:css加载会阻塞DOM树的渲染
-
3:css加载会阻塞后面js语句的执行
现在让我们理解一下概念。 回流:当我们的render树需要遇到更改元素的尺寸,布局、现隐等操作时,需要重新构建render 树(css+dom连接在一起时形成render tree)。 重绘:当render treee中例如颜色,背景颜色,边框颜色等只影响到外观的属性变化时叫做重绘。
笼统的打个比方:我们都知道在建造房子时房梁,基角都是首先搭建好然后再进行内部的装修补墙纸等操作画了一张图大概就能明白回流和重绘的一个概念。
在图片中我们修建一个房子时黑色的线条就相当于我们的回流,而拆字以及黄色的门则相当于我们的重绘操作。所以我们可以知道回流相比较重绘代价更高,回流的花销与render tree的节点有关系,当然浏览器会优先帮我们做一些优化操作比如把所有会引起回流、重绘的操作放入这个队列,等队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会flush队列,进行一个批处理。这样就会让多次的回流、重绘变成一次回流重绘。 当然上面是浏览器的操作那么在实际的编写项目中我们其实可以规范我们的代码质量尽量减少回流操作,总结了一些代码中的常见技巧:
- 1:合并所有的属性改变
let el = document.getElementById('test');
el.style.cssText += 'border-left: 1px; border-right: 2px; padding: 5px;';
-
2:需要对DOM进行一系列的修改时我们可以这样来弄来减少页面的回流次数。 将元素脱离文档流(通常可以隐藏元素、使用文档片段、拷贝元素到脱离文档中),然后进行多次修改再最后带回我们的dom中,例如我们需要对一个表格增加10个td元素通常的写法我们会这样干:
``` let parentDom = document.getElementById('table'); let td; for(let i=0;i<10;i++){ td = document.createElement('td'); td.innerText = "测试" parentDom.appendChild(td); } ``` 在以上的代码中每次循环都会插入一个新的节点,会导致浏览器回流一次,那么如果插入节点过多时会导致....(省略一万字)所以有了下方操作代码: 1隐藏脱离文档流 ``` let parentDom = document.getElementById('table'); parentDom.style.display = 'none' for(let i=0;i<10;i++){ td = document.createElement('td'); td.innerText = "测试" parentDom.appendChild(td); } parentDom.style.display = 'block' ``` 2: 使用cloneNode函数克隆table节点然后执行增加td操作然后使用replaceChild函数替换节点即可 3:使用createDocumentFragment创造元素然后添加td元素最后parentDom appendChild元素即可
3:对于复杂的动画来说我们也可以通过绝对定位让他先暂时脱离文档流然后再进行相关操作之后再丢回原本的dom中去。
当然技巧还有很多,具体问题具体分析先暂时开个头,下一篇聊一下前端在部署时我们可以给运维人员提的一些帮助页面性能体验的一些配置(nginx)。