【问题标题】:How can I tell when the browser stops repainting DOM layers/nodes because they are obscured?我如何知道浏览器何时停止重新绘制 DOM 层/节点,因为它们被遮挡了?
【发布时间】:2024-05-29 12:00:01
【问题描述】:

识别: 我正在寻找所有可能的解决方案,以检测由于浏览器优化性能而导致浏览器中 FPS 下降或重绘/重排停止发生的时间,因为文档的某个区域不在视野范围内。

观察: 到目前为止,我研究过的大多数原生 HTML/JS 解决方案都没有考虑到 DOM 的部分,它被页面的其他部分或首屏下方的 DOM 遮挡。虽然有时内容会直接嵌入到父文档中,但有时它可能位于框架或 iframe 中。

测试结果: mozPaintCount 是窗口的 dom 回流的准确表示,当窗口或框架中的文档被遮挡时会正确响应。似乎 Firefox 正在正确识别 dom 的某些部分,并且在它们被遮挡时不会重新绘制它们,当某些东西不在视线范围内时,可以通过 Firefox 检查器工具进行视觉检查,但是检查器在绘制时可能不会考虑视图层次结构重绘区域的亮点。向你致敬,Mozilla!

参考:mozPaintCount

Flash 在屏幕外时也会显示 FPS 减慢,而最新的 Flash Player 11.2 有一个专用事件,当它因优化原因被浏览器限制时会触发。 Flash 也不是一个值得信赖的解决方案,因为它在许多浏览器中默认被禁用。

参考:Flash Player 11.2 Throttle Events

页面可见性更改事件的当前浏览器实现能够在窗口已更改为另一个选项卡或窗口变为非活动状态时进行广播,但不考虑折叠下方的元素/窗口/文档的滚动位置或被其他dom遮住了。然而,在本规范的第二稿中,建议浏览器考虑视口和 DOM 层次结构以提供更准确的结果。

参考:Recommendation Page Visibility, 2011Draft Page Visibility 2, 2013

当元素被遮挡时,CSS 过渡似乎没有被优化掉,因此无法正确测量。我尝试了许多导致回流的不同属性(高度、宽度、盒子阴影等),但无法从中获得任何有意义的指标。

requestAnimationFrame 似乎仅在选项卡更改且浏览器窗口变得模糊时才会限制动画,但不处理首屏以下的内容。另外,因为 raf 只附加在窗口级别,它无法绑定到特定的 dom 节点(这在其实现中似乎是短视的)。

参考:requestAnimationFrame

我还没有完成对 WebGL 的测试,但这仅限于少数现代浏览器(考虑到旧浏览器的 Flash 解决方案,这是可以接受的结果)。

我还没有完成对画布的测试,但这可能是一个很好的解决方案,因为它受到比 WebGL 更广泛的浏览器的支持。

我什至还没有开始考虑嵌入式对象以及它们可以提供什么。

我还没有研究过 ActiveX 控件是否有任何帮助。

我没有看过 HTML5 视频。

动画 GIF 似乎只在 Firefox 中进行了优化。再次向 Mozilla 致敬!

因此,每个浏览器供应商如何优化页面渲染的神秘和魔力继续扼杀我的进步。但是,不能仅依靠元素位置来真正指示元素是否实际可见,因为页面可能有其他层会遮盖框架内容,或者内容可能以排除任何有意义的可见呈现的方式显示(例如更改内容的 3d 旋转使其不可见。)

欢迎就浏览器如何实际优化显示内容或其他说明或对此问题的实际答案进行头脑风暴。

同样,here is an older SO question 也部分包含了这个问题。

【问题讨论】:

  • 有趣的观察!因此,为了重新表述您的问题/问题,您希望有一个requestAnimationFrame 绑定到页面的特定区域并在该区域不在视图中时受到限制?我认为您的措辞“如何检测内部浏览器行为”没有一个好的答案。
  • 目标是检测节点何时不再可见以防止一些昂贵或重复的任务吗?例如,如果聊天窗口不再可见,您可以停止接收新消息。
  • 没错,贾斯汀。目标是优化页面的响应并允许 javascript 做出相应的反应。在现有的解决方案中,除了检查该组件附近插件的重绘计数或帧速率之外,没有真正的方法可以知道是否正在查看或正在查看加载的组件。因为浏览器没有公开他们在哪里进行优化,所以假设的答案似乎是“你不能”,这似乎是不正确的。
  • 此外,我还想知道哪些部分得到了优化,哪些没有在不同的浏览器中测试不同元素的性能方面。一个很好的例子是动画 gif,它会在除 Firefox 之外的所有浏览器中不断重绘区域。

标签: javascript performance dom dom-events requestanimationframe


【解决方案1】:

我在以下代码中使用了 Mozilla mozPaintCount,但没有得到预期的 FPS 值。

第 1 部分:运行此代码一次以填充变量。

var currentFrames = window.mozPaintCount, currentTime = new Date();

第 2 部分:在第 1 部分之后随时运行此代码。

(window.mozPaintCount - currentFrames)/((new Date() - currentTime)/1000)

结果显示 FPS,对于我的网站,我得到 9FPS。 Chrome FPS 计数器显示 60FPS。

总体而言,浏览器的页面渲染性能是 Web Dev World 中一个相对较新的话题。除了 Chrome DevTools,其他所有主要供应商似乎都对公开工具以提高性能没有太大兴趣。由于对网页渲染性能的兴趣有限,因此大量数据也是如此。

开发人员关注的主要性能理念是。 滚动性能、绘制时间的 CSS 效果、您提到的动画 Gif,当然还有 requestAnimationFrame。 http://www.html5rocks.com/en/tutorials/speed/unnecessary-paints/

真的,在首先进入这个领域之前,我建议您花一点时间真正了解浏览器在呈现您的页面和更新该页面时做了什么。 http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/

我会为你添加更多链接,但我的 SO 代表太低了。

【讨论】:

    【解决方案2】:

    关于你写的关于 requestAnimationFrame 的内容:

    另外,因为raf只附加在窗口级别,无法绑定到特定的dom节点

    您可以(理论上)让代码在 iframe 中运行,因此 window 对象是整个元素,或者 1px iframe 可能是您内容上的一个点。

    我通过查看 mozPaintCount(正如您所说以及 @alexK85 在他们的回答中所建议的那样)在 Firefox 中进行了这项工作,以查看 CSS 更改后是否有重绘(当 iframe 发生 CSS 更改后,浏览器不会立即重绘出视口)。 但是,我还不能在其他浏览器中使用 requestAnimationFrame 做类似的事情来确定是否在 CSS 更改后立即重绘 iframe。

    有人对如何使用 raf 来确定浏览器是否进行重绘有任何建议吗?

    【讨论】:

    • mozPaintCount 支持是捕获重绘的唯一方法,因为所有其他浏览器都基于 top.window 测量优化,随后不会根据视口内的位置进行节流。对于其他受支持的浏览器,您可以使用 Flash 收集此统计信息并进行报告。在旧的 IE 中,您将使用鼠标事件来对页面中的位置进行三角测量,因为它们会在 8-10 中泄漏信息。然而,8 并没有给你窗口大小,所以你只剩下 9 和 10。
    • @JeffreyGilbert 好的,感谢您添加。许多组织声称能够跨浏览器做到这一点,因此他们必须将 Flash 用于 FF 以外的浏览器。这篇论文非常有用pdrf.net/wp-content/uploads/2013/11/38deJager.pdf(参见第 6 页的表格),但是关于 Flash 依赖的措辞是模棱两可的。
    • 为了消除歧义,Flash 有时有效,有时无效。它需要安装 Flash 才能读取节流信息,但安装 Flash 甚至是特定版本并不能简单地使其工作。这种支持会根据 Flash 所处的环境而变化,并且需要在签入时使用替代测量技术,例如 Firefox,您可以在其中使用痛苦计数或几何 API 来补偿。
    • 其他浏览器,例如 Internet Explorer,有时会有一些您可以利用的怪癖。我只能根据 IE 9 和 10 中窗口镶边的假设来检查几何图形,而将 IE 抛在后面,因为如果我只是尝试将广告捕获为“在屏幕上”与“在视口中”,它会扭曲结果