Web性能优化系列:预防布局抖动

预防“布局抖动”

布局抖动是因 JavaScript 的 DOM 元素被多被次暴力写,然后读,导致文档重排而出现的。

当DOM元素被写入值,布局就“无效”,而多次这样就会导致文档重排。浏览器很懒,它总想等到当前操作(或帧)的最后一步才重排。

然而,如果在当前操作(帧)完成前,从DOM元素中获取值,这会迫使浏览器提早执行布局操作,这称为“强制同步布局”,这可是性能杀手!

布局抖动的副作用在现代桌面浏览器上并不明显;但对于低配置的移动设备来说,其后果就不堪设想了。

能快速修复?

在理想情况下,我们可能通过简单地重复执行,以至于将DOM元素的读写操作放在一起执行。这意味着文档只需重排一次即可。

现实情况会怎么样?

现实情况并非如此简单。大型应用程序的代码会分散到各个地方,因此这些地方都有危险的DOM操作。所以不能简单地(绝对不应该)聚集它们,而需要解耦代码,只是需要控制好执行顺序。那如何让读写操作捆绑在一起,从而获得最佳性能呢?

进入requestAnimationFrame

window.requestAnimationFrame是一个将操作安排在下一帧一起执行的函数,类似于setTimeout(fn, 0)。这是非常有用的,因为能使用它来安排所有DOM的写操作在下一帧一起执行,保留所有DOM的读操作在当前同步状态。

这意味着我们能很好地封装代码了。经过小小调整后的代码,就将高耗能的DOM操作捆绑在一起!实在太棒了!

工作实例

我创建了一个工作案例来证明这个观点。从第一个截屏的chrome时间轴可看出,有多个布局抖动穿插其中。

Before After

在改用requestAnimationFrame 后,仅仅只触发一次布局事件,其结果是操作快了约96%。

它具有伸缩性吗?

在一个简单案例里,使用requestAnimationFrame来延迟DOM写操作,从而大大提高性能,但这项技术没有伸缩性可言。

在我们的应用中,可能需要在DOM元素上执行先写后读操作,然后再次掉入布局抖动的坑,只是在不同帧。

我们可以将读操作放到另外一个requestAnimationFrame ,但我们不能保证应用程序的另一部分,没有把写操作放在同一帧上。

介绍 ‘FastDom’

FastDom是一个轻量的库,它提供一个公共接口,能让DOM的读/写操作捆绑在一起。其实,它就是利用上述同样的 requestAnimationFrame 技术来大大提高DOM操作速度。

FastDom通过接收读写操作,并在下一帧捆绑它们(先读后写),从而消除DOM的相互影响。这意味着我们能独立编写应用程序组件,而不用担心它们在应用程序中互相影响。

使用FastDom的启示

通过使用FastDom,会让所有DOM任务变成异步,这意味着你不能总是假设DOM将会以什么状态进行操作。操作从之前的同步,变成现在的异步方式。因此,可能没执行完异步处理函数就会执行下一步操作了。

要解决这一点,我打算用事件系统来明确操作何时完成,和明确依赖于完成后所做出的响应操作。

虽然所做工作是一样的,但能通过增加代码量来显著提高性能。我个人认为这个代价小。

FastDom案例

完善FastDom

web应用缺少一个明确的方式,来解决布局抖动问题。正如一个应用程序很难协调所有不同的部分,来确保产品最终是高效的。如果FastDom能为开发者们提供一个简单接口来解决这个问题,那只能意味着它是个好东西。

瞧一瞧 FastDom 项目,欢迎随时通过 pull requests 或 filing issues 来完善它。

打赏支持我翻译更多好文章,谢谢!

打赏译者

打赏支持我翻译更多好文章,谢谢!

任选一种支付方式

1 6 收藏 3 评论

关于作者:刘健超-J.c

前端,在路上...http://jchehe.github.io 个人主页 · 我的文章 · 19 ·     

相关文章

可能感兴趣的话题



直接登录
最新评论
跳到底部
返回顶部