浏览器渲染流水线解析(四)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

5 非合成器动画性能分析和优化指南

前面已经我们已经把非合成器动画区分为 Blink 触发,无法由合成器运行的动画和由 Timer/RAF 驱动的 JS 动画两类,因为前者可以认为是后者的一个简化版本,所以这一章主要讨论 Timer/RAF 驱动的 JS 动画。

5.1 动画流水线

Blink Animation

从上图可以看出非合成器动画的流水线比合成器动画更长更复杂,并且非合成器动画的后半段跟合成器动画是一致的。

  1. JavaScipt 部分是页端实现的逻辑,可能包含了计算的部分,和调用浏览器提供的 API 的部分(修改 DOM 树,CSS 属性等),最终改变了网页的内容;
  2. 网页内容被改变会导致 Blink 生成新的 MainFrame,MainFrame 包括了重排版,更新图层树,和重新记录发生变更的图层的内容,生成新的 DisplayList,等等;
  3. Blink 生成新的 MainFrame 后需要向合成器发起 Commit 的请求,合成器在 Commit 过程中根据 MainFrame 生成自身的图层树,Blink 在 Commit 的过程中保持阻塞状态,Commit 完成后再继续运行;
  4. 合成器实际上有两棵图层树,新提交的 MainFrame 生成的是 Pending 树,用于绘制 Draw 的是 Active 树,只有当 Pending 树当前可见区域部分的分块全部完成 Rasterize 后,才会进入 Active 步骤,在 Active 的过程中,Pending 树相对于 Active 树的变更部分才会被同步到 Active 树;
  5. Active 后,合成器会向 UI 线程的窗口管理器发起重绘请求,窗口管理器会在下一个 VSync 的时候开始绘制新的一帧,后面的流程就跟合成器动画是一样的了;

上述流程的一些关键点是:

  1. 在合成器动画中,分块没有完成光栅化,出现空白是被允许的,这样浏览器可以更好地保证合成器动画的帧率,但是在非合成器动画中出现空白是不被允许的,因为新的 MainFrame 常常会带来大面积的变更,如果允许空白的话可能会出现非常不好的视觉效果。这样就导致合成器需要使用两棵图层树来构建一个类似双缓冲的机制,只有当 Pending 树在后台完成可见区域的光栅化时才被允许同步到 Active 树;
  2. 在非合成器动画过程中,Main Frame N,Main Frame N Active;Compositor Frame N,GL Frame N 这四个 Block 基本上可以认为是可以并发运行的(唯一会阻塞的环节是 Commit,不过 Commit 耗时一般不长),理论上我们要实现 60 帧的非合成器动画,只需要保证其中每个 Block 的耗时总和小于 16.7 毫秒即可。当然实际的状况下,在移动设备上很难实现这么多线程完全并发运行,加上过多线程带来的互相通讯的开销,使得每个 Block 的最大允许耗时实际上是小于 16.7 毫秒的;

5.2 动画耗时分析和优化指南

  1. JavaScipt 的耗时是由页端自己的逻辑决定的,一般超过 10 毫秒就基本上很难实现 60 帧的非合成器动画了;
  2. MainFrame 的耗时主要取决于网页 DOM 树,图层树的复杂程度和变化程度,在变更很小,比如只有几个元素的内容发生变化,图层树不变的情况下,一般耗时都是在 3 ~ 5 毫秒左右,如果变更很大,几十甚至几百都是有可能的;
  3. Commit 的耗时主要取决于图层树的复杂程度,一般耗时都很短,大概 2 ~ 3 毫秒上下;
  4. Rasterize 的耗时范围变化极大,取决于网页内容的复杂程度和新 MainFrame 在当前可见区域内网页内容发生变化的总面积,另外图片解码也发生在这个阶段,而图片解码也是光栅化耗时最多的一个环节,光栅化的耗时从几毫秒到几百毫秒都有可能(图片在第一次被光栅化时被解码,一直在可见区域内的图片不会被反复重解码);
  5. Active 跟 Commit 的耗时类似,主要取决于图层树的复杂程度,一般耗时很短,大概 2 ~ 3 毫秒上下;

总的来说对非合成器动画性能影响最大的通常是 JavaScript 和 Rasterize,要实现高性能的非合成器动画,页端需要很小心地控制 JavaScript 部分的耗时,并避免在每一帧中引入大面积的网页内容变化和大幅度的图层结构变化。另外非合成器动画的后半段就是合成器动画,所以对合成器动画的性能优化要求也同样适应于非合成器动画。

另外对于 WebGL 来说,当在 JavaScript 里面调用 WebGL API 时,这些命令只是被 Chrome 缓存起来,并不会在 Renderer 线程调用真正的 GL API,所以 WebGL API 在 JavaScript 部分的耗时只是一个 JS Binding 调用的 Overhead,最终绘制 WebGL 内容的 GPU 耗时实际上是被包含在最后的 GPU 的步骤里面。但是在移动平台上一个 JS Binding 调用的 Overhead 是相当高的,大概在 0.01 毫秒这个范围,所以每一帧超过 1000 个 WebGL API 调用的 WebGL 游戏,性能阻塞的瓶颈有很大概率会出现在 JavaScript 也就是 CPU 上,而不是 GPU。

目录
相关文章
|
4月前
|
JavaScript 前端开发 搜索推荐
CSR、SSR与同构渲染全方位解析
CSR、SSR与同构渲染全方位解析
65 0
|
5月前
|
缓存 JavaScript 前端开发
浏览器渲染:理解页面加载的幕后工作
浏览器渲染:理解页面加载的幕后工作
|
2月前
|
JavaScript 前端开发 算法
【Vue秘籍揭秘】:掌握这一个技巧,让你的列表渲染速度飙升!——深度解析`key`属性如何成为性能优化的秘密武器
【8月更文挑战第20天】Vue.js是一款流行前端框架,通过简洁API和高效虚拟DOM更新机制简化响应式Web界面开发。其中,`key`属性在列表渲染中至关重要。本文从`key`基本概念出发,解析其实现原理及最佳实践。使用`key`帮助Vue更准确地识别列表变动,优化DOM更新过程,确保组件状态正确维护,提升应用性能。通过示例展示有无`key`的区别,强调合理使用`key`的重要性。
49 3
|
2月前
|
JavaScript 算法 前端开发
"揭秘Vue.js的高效渲染秘诀:深度解析Diff算法如何让前端开发快人一步"
【8月更文挑战第20天】Vue.js是一款备受欢迎的前端框架,以其声明式的响应式数据绑定和组件化开发著称。在Vue中,Diff算法是核心之一,它高效计算虚拟DOM更新时所需的最小实际DOM变更,确保界面快速准确更新。算法通过比较新旧虚拟DOM树的同层级节点,递归检查子节点,并利用`key`属性优化列表更新。虽然存在局限性,如难以处理跨层级节点移动,但Diff算法仍是Vue高效更新机制的关键,帮助开发者构建高性能Web应用。
53 1
|
2月前
|
运维 测试技术 持续交付
部署流水线解析
部署流水线解析
27 1
|
3月前
|
JavaScript 前端开发 搜索推荐
服务器端渲染技术SSR与ISR:深入解析与应用
【7月更文挑战第20天】服务器端渲染(SSR)和增量静态再生(ISR)作为现代Web开发中的两种重要渲染技术,各有其独特的优势和适用场景。在实际应用中,开发者应根据具体需求和条件选择合适的渲染模式。无论是追求极致的页面加载速度和SEO优化,还是实现内容的实时更新,SSR和ISR都能提供有效的解决方案。通过深入理解这些技术的工作原理和应用场景,开发者可以构建出更加高效、可靠和用户体验优异的Web应用。
|
4月前
|
移动开发 前端开发 JavaScript
浏览器端图表渲染技术SVG, VML HTML Canvas
浏览器端图表渲染技术SVG, VML HTML Canvas
29 0
|
5月前
|
存储 编解码 API
【解码与渲染 异常情况】深入解析视频中绿色竖线现象(一)
【解码与渲染 异常情况】深入解析视频中绿色竖线现象
172 6
【解码与渲染 异常情况】深入解析视频中绿色竖线现象(一)
|
5月前
|
缓存 图形学 异构计算
【Shader渲染流水线流程】
【Shader渲染流水线流程】
|
5月前
|
存储 编解码 算法
【解码与渲染 异常情况】深入解析视频中绿色竖线现象(二)
【解码与渲染 异常情况】深入解析视频中绿色竖线现象
121 1

推荐镜像

更多
下一篇
无影云桌面