发表于: 2019-11-27 23:39:22

1 1082


今日完成的事、

      调试消息接口

明日计划的事

       继续调整接口

收获

       为什么说JS的DOM操作很耗性能

渲染 HTML 的过程

当浏览器下载完所有页面 HTML 标记,JavaScript,CSS,图片之后,它解析文件并创建两个内部数据结构:一个DOM Tree树表示页面结构,一个是 CSSOM Tree表示DOM节点如何显示。

把DOM Tree 和 CSSOM Tree结合在一起,就成为 Render Tree(渲染树)。

浏览器根据渲染树计算每一个节点的几何信息。这个就叫做重排(Relayout,更专业的叫法应该是回流(Reflow)。

根据计算好的几何信息,绘制页面。这个就叫做重绘(Repainting)。

重绘是一个非常昂贵的操作。浏览器完成一个dom操作,大多时间都是花费在重绘上面的。

什么叫做重排、重绘?在文章后面有介绍。

为什么很“慢”

通过学习,我总结出来,有两个方面。

1)浏览器响应 DOM操作 需要一定的成本。程序跑起来都是要花时间的嘛,对我们开发者来说,在乎的是这个时间的长短,更直观的说法就是卡顿是否肉眼可见。

2)第二点的说法更关乎技术。

Dom操作是由 javaScript 实现的。

浏览器对于DOM操作的响应,是同步的。

基于这两点,大家想想这种业务场景:

在这个代码中,可以知道,一个 li 的操作,是会引起浏览器的重排重绘的。

DOM是由 js 实现的,但 js 又是单线程。在这个代码中,每一个li的操作改变,都被存储在js内存当中。

也就是说,只有在等 js 代码跑完了之后,浏览器才会开始响应这段代码所带来的 js 操作。这些操作扎堆在一起等来浏览器来响应。浏览器的响应又是同步的,所以它只能一次一次去执行重排计算,渲染,再计算,再渲染。。。

这样,效率其实很低。重排,重新渲染的计算量完全取决于 DOM操作 的影响范围。可能这时,你会想,浏览器就不能智能一点吗?几次操作一次计算,一次渲染不就好了?

嗯。。。也许浏览器有它自己的考虑。


重排

想要了解重排,要先知道:浏览器渲染页面默认采用的是流式布局模型;

所谓重排,实际上是根据渲染树中每个渲染对象的信息,计算出各自渲染对象的几何信息(DOM对象的位置和尺寸大小),并将其安置在界面中的正确位置。

从这个意思来看,某一个DOM节点信息更改了,就需要对DOM结构进行重新计算,重新布局界面,只是这个结构更改程度会决定周边DOM更改范围,即全局范围和局部范围。

全局范围就是从根节点 html 开始对整个渲染树进行重新布局,例如当我们改变了窗口尺寸或方向或者是修改了根元素的尺寸或者字体大小等;而局部布局可以是对渲染树的某部分或某一个渲染对象进行重新布局。

重排一定会引起重绘。

在此,总结会引起重排的操作有:

页面首次渲染。

浏览器窗口大小发生改变。

元素尺寸或位置发生改变。

元素内容变化(文字数量或图片大小等等)。

元素字体大小变化。

添加或者删除可见的DOM元素。

激活CSS伪类(例如::hover)。

设置style属性

查询某些属性或调用某些方法。

重绘

相比重排,重绘就简单多了,所谓重绘,就是当页面中元素样式的改变并不影响它在文档流中的位置时,例如更改了字体颜色,浏览器会将新样式赋予给元素并重新绘制的过程称。

优化方案

DOM操作的背后,隐藏这不止止是文中所描述的这些代价。为了给用户更好的浏览体验,可以有以下优化的方案:

减少DOM操作

如果在一个局部方法中需要多次访问同一个dom,则先暂存它的引用

采用更高效的API或者更高效的写法

1)用querySelectorAll()替代getElementByXX()。

2)开启动画的GPU加速,把渲染计算交给GPU

3)用事件委托来减少事件处理器的数量。

4)使用react、vue等页面框架来编写View页面。react采用虚拟dom,尽可能的讲多次重排浓缩成一次。

减少重排

CSS及动画处理

1)用更高效的css3效果,通过类名控制动画,尽量避免直接操作DOM属性;

2)在动画的元素多嵌套一层div,尽量用绝对定位或者固定定位使其脱离文档流,再进行动画处理;

3)尽量在滚动的时候,停止动画;

4)动画实现的速度选择。以1px移动最为平滑,但是reflow就会果与频繁,建议以3px移动则会好很多。



返回列表 返回列表
评论

    分享到