3

我试图理解为什么我有几个由 Chrome 开发工具报告的长帧。

在此处输入图像描述

火焰图中的第一行(调用堆栈的顶部)主要是Timer Fired事件,由jQuery.Deferred()s 执行一堆$(function(){ });准备好的函数触发。

如果我深入研究 jQuery 源代码并用火焰图替换它们的使用setTimeoutrequestAnimationFrame没有太大变化,我仍然会在单个帧内触发许多 rAF(如开发工具报告的那样),从而产生长帧。我本来希望做下面的伪代码:

window.requestAnimationFrame(function() {
    // do stuff
});

window.requestAnimationFrame(function() {
    // do more stuff
});

在两个不同的动画帧上执行。不是这样吗?

所有正在执行的 JS 都是必要的,但是我应该怎么做才能将它作为“微任务”执行(如暗示,但此处未解释https://developers.google.com/web/fundamentals/performance/rendering/ optimize-javascript-execution)何时setTimeout并且rAF似乎没有实现这一点。

更新

这是其中似乎没有任何回流(强制或以其他方式)的长帧之一的放大照片。为什么这里所有的 rAF 回调都是在一帧内执行的?

在此处输入图像描述

4

1 回答 1

6

长帧通常是由强制同步布局引起的,即您(无意)强制布局操作提前发生。

写入 DOM 时,布局需要回流,因为它已被写入操作无效。这通常发生在下一帧。但是,如果您尝试从 DOM 中读取,则布局会在当前帧中较早发生,以确保返回正确的值。当发生强制布局时,会导致长帧,从而导致卡顿。

为防止这种情况发生,您应该只在requestAnimationFrame函数内部执行写操作。读取操作应该在此之外进行,以避免浏览器进行早期布局。

Diagnose Forced Synchronous Layouts是一篇很好解释的文章,并且有一个简单的示例演示,用于检测 DevTools 中的强制回流,以及如何解决它。

可能还值得一试 FastDom,这是一个用于批量读取和写入的库。它基本上是一个排队系统,并且更具可扩展性。

附加来源: 什么强制布局/回流,作者 Paul Irish,包含将强制布局/回流的属性和方法的综合列表。

更新:关于多个调用将在不同帧上执行回调的假设,requestAnimationFrame情况并非如此。当您有连续调用时,浏览器会将回调添加到动画回调的文档列表中。当浏览器开始运行下一帧时,它会遍历文档列表并按照添加的顺序执行每个回调。

有关更多实现细节,请参阅HTML 规范中的动画帧

这意味着您应该避免使用连续调用,尤其是在回调函数执行时间加起来超过您的帧预算的情况下。我认为这可以解释不是由回流引起的长帧。

于 2017-01-16T01:18:20.500 回答