网页内容如何影响电量使用

用户在移动设备上花费了大量的在线时间,而其余大部分用户则使用非插电笔记本电脑。对于这两者而言,电池续航都至关重要。在这篇文章中,我们将讨论影响电池续航的因素,以及作为一名网页开发者,您如何才能使您的页面更省电,从而让用户能够花更多时间与您的内容互动。

哪些部分消耗电量?

移动设备的大部分电量被以下几个主要组件消耗:

  • CPU(主处理器)
  • GPU(图形处理)
  • 网络(Wi-Fi 和蜂窝无线芯片)
  • 屏幕

屏幕的电量消耗相对恒定,并且主要由用户控制(通过屏幕开启时间和亮度),但其他组件,即 CPU、GPU 和网络硬件在电量消耗方面具有高动态范围。

系统会根据当前正在处理的任务调整 CPU 和 GPU 的性能,这当然包括渲染用户在网页浏览器中互动以及其他使用网页内容的应用程序的网页。这是通过开启或关闭某些组件以及改变其时钟频率来实现的。广义上讲,芯片所需的性能越高,其能效就越低。硬件可以非常快速地提升到高性能(但会带来巨大的电量消耗),然后迅速回到更高效的低功耗状态

良好电量使用的通用原则

因此,为了最大限度地延长电池续航时间,您需要减少在高功耗状态下花费的时间,并尽可能让硬件回到空闲状态。

对于网页开发者而言,有三种互动状态需要考虑:

  • 当用户正在积极地与内容互动时。
  • 当页面位于最前端,但用户未与其互动时。
  • 当页面不是最前端内容时。

高效的用户互动

显然,在用户与页面互动时消耗电量是合理的。您希望页面加载迅速,并快速响应触摸操作。在许多情况下,减少首次绘制时间(time to first paint)和用户可交互时间(time to user interactive)的优化措施,也能降低电量消耗。然而,请注意避免在初始页面加载后继续加载资源和运行脚本。目标应该是尽快回到空闲状态。总的来说,运行的 JavaScript 越少,页面的能效就越高,因为脚本是在浏览器已经完成页面布局和绘制工作之上的额外工作。

页面加载后,用户的互动操作,如滚动和点击,也会增加硬件功耗(主要是 CPU 和 GPU),这同样是合理的,但请确保在用户停止互动后尽快回到空闲状态。此外,尽量保持在浏览器的“快速路径”上——例如,正常的页面滚动会比用 JavaScript 实现的自定义滚动省电得多。

将空闲时的电量使用降至零

当用户不与页面互动时,尽量让页面使用尽可能少的电量。例如:

  • 尽量减少计时器的使用,以避免唤醒 CPU。尝试将基于计时器的工作合并到几个不频繁的计时器中。大量不协调的计时器频繁触发 CPU 唤醒,这比将这些工作集中到更少的块中要糟糕得多。
  • 尽量减少持续动画内容,如动画图片和自动播放视频。要特别警惕,避免使用“加载”旋转 GIF 或持续触发绘制的 CSS 动画,即使您看不到它们。IntersectionObserver 可用于仅在动画可见时才运行它们。
  • 尽可能使用声明式动画(CSS 动画过渡)。当动画内容不可见时,浏览器可以优化掉这些动画,并且它们比脚本驱动的动画更高效。
  • 避免使用网络轮询从服务器获取周期性更新。请使用WebSockets或具有持久连接的Fetch,而不是轮询。

一个本应空闲却仍在工作的页面,其对用户互动的响应也会变慢,因此,最小化后台活动既能提高响应速度,也能延长电池续航时间。

后台运行时 CPU 零使用率

有多种情况会导致页面处于非活动状态(非用户主要焦点),例如:

  • 用户切换到不同的标签页。
  • 用户切换到不同的应用程序。
  • 浏览器窗口最小化。
  • 浏览器窗口可见但不是焦点窗口。
  • 浏览器窗口在另一个窗口后面。
  • 窗口所在的空间不是当前空间。

当页面变为非活动状态时,WebKit 会自动采取措施来节省电量:

此外,WebKit 利用操作系统提供的功能来最大限度地提高效率:

  • 在 iOS 上,标签页在可能的情况下会完全挂起。
  • 在 macOS 上,标签页会参与App Nap,这意味着一个没有视觉更新的标签页的网页进程会获得较低的优先级,并且其计时器会受到限制。

然而,页面可以通过计时器(setTimeoutsetInterval)、消息、网络事件等触发 CPU 唤醒。您应该尽可能避免在后台发生这些情况。有以下两个 API 对此很有用:

  • Page Visibility API(页面可见性 API)提供了一种响应页面在后台和前台之间切换的方式。这是一种很好的方法,可以避免在页面处于后台时更新 UI,然后在页面可见时使用visibilitychange 事件来更新内容。
  • 每当页面不再获得焦点时,就会发送blur 事件。在这种情况下,页面可能仍然可见,但它不是当前获得焦点的窗口。根据页面情况,停止动画可能是一个好主意。

发现问题的最简单方法是使用 Web Inspector 的时间轴(Timelines)。在页面处于后台时,记录不应显示任何事件发生。

寻找电量消耗低效问题

现在我们已经了解了网页电量消耗的主要原因,并提供了一些创建高效内容的通用规则,接下来我们来讨论如何识别和解决导致过度电量消耗的问题。

脚本

如上所述,现代 CPU 可以在设备空闲时将功耗从非常低的水平迅速提升到非常高的水平,以满足用户互动和其他任务的需求。因此,CPU 是导致电池续航变化的主要原因。页面加载期间的 CPU 使用量是浏览器引擎加载、解析和渲染资源以及执行 JavaScript 所做工作的总和。在许多现代网页上,执行 JavaScript 所花费的时间远远超过浏览器在加载过程其余部分所花费的时间,因此最小化 JavaScript 执行时间将对电量消耗带来最大的好处。

衡量 CPU 使用率的最佳方法是使用 Web Inspector。正如我们在之前的一篇文章中所示,时间轴现在显示了任何选定时间范围内的 CPU 活动。

为了高效利用 CPU,WebKit 在可能的情况下会将工作分配到多个核心(使用 Worker 的页面也能够利用多个核心)。Web Inspector 提供了与页面主线程并发运行的线程的详细分解。例如,以下截图显示了在滚动一个具有复杂渲染和视频播放的页面时,线程的情况:

在寻找优化点时,请专注于主线程,因为那是您的 JavaScript 运行的地方(除非您使用 Worker),并使用“JavaScript 和事件”时间轴来了解是什么触发了您的脚本。也许您在响应用户或滚动事件时做了过多的工作,或者从 requestAnimationFrame 触发了隐藏元素的更新。请注意您在页面上使用的 JavaScript 库和第三方脚本所做的工作。要深入挖掘,您可以使用 Web Inspector 的JavaScript 分析器来查看时间花费在哪里。

“WebKit 线程”中的活动主要由与 JavaScript 相关的工作触发:JIT 编译和垃圾回收,因此减少运行的脚本量以及减少 JavaScript 对象的流失应该会降低这些活动。

WebKit 调用的各种其他系统框架也使用线程,因此“其他线程”包括这些框架所做的工作;“其他线程”活动的最大贡献者是绘制,我们将在接下来讨论。

绘制

主线程 CPU 使用率也可能由大量的布局和绘制触发;这些通常由脚本触发,但除了transformopacityfilter之外的 CSS 属性动画也可能导致这些。查看“布局和渲染”时间轴将帮助您了解是什么导致了活动。

如果“布局和渲染”时间轴显示有绘制活动,但您不清楚是什么发生了变化,请打开“绘制闪烁”(Paint Flashing)功能。

这将导致这些绘制区域短暂地以红色叠加层高亮显示;您可能需要滚动页面才能看到它们。请注意,WebKit 会保留一些“过度绘制”的图块以实现平滑滚动,因此即使在视口中不可见的绘制也可能仍在工作以保持屏幕外图块的最新状态。如果时间轴中显示了绘制活动,则表示它正在进行实际工作。

除了导致 CPU 消耗电量外,绘制通常还会触发 GPU 工作。macOS 和 iOS 上的 WebKit 使用 GPU 进行绘制,因此触发绘制会导致电量显著增加。额外的 CPU 使用率通常会显示在 CPU 使用时间轴的“其他线程”下。

GPU 也用于<canvas>渲染,包括 2D canvas 和 WebGL/WebGPU。为了最小化绘制,如果 canvas 内容没有变化,请不要调用 <canvas> API,并尝试优化您的 canvas 绘制命令。

许多 Mac 笔记本电脑都有两个 GPU,一个“集成”GPU,它与 CPU 在同一个芯片上,功能较弱但更省电;另一个是更强大但更耗电的“独立”GPU。WebKit 默认使用集成 GPU;您可以使用powerPreference上下文创建参数请求独立 GPU,但仅在您能证明其功耗成本合理的情况下才这样做。

网络

无线网络会以意想不到的方式影响电池续航。手机受影响最大,因为它们结合了强大的无线电(Wi-Fi 和蜂窝网络芯片)和较小的电池。不幸的是,在实验室之外测量网络对电量的影响并不容易,但可以通过遵循一些简单规则来减少。

减少网络功耗最直接的方法是最大限度地利用浏览器的缓存。所有旨在缩短页面加载时间的最佳实践,也通过减少无线电芯片需要通电的时间来延长电池续航。

另一个重要方面是将网络请求按时间分组。每当有新请求到来时,操作系统都需要打开无线电,连接到基站或蜂窝塔,并传输字节。传输数据包后,无线电会保持通电一小段时间,以防传输更多数据包。

如果页面不经常传输少量数据,则开销可能会大于传输数据所需的能量。

Networking Power Overhead of transmitting 2 packets with a delay between them

此类问题可以在 Web Inspector 的网络请求时间轴中发现。例如,以下屏幕截图显示了在几秒钟内发送的四个独立请求(可能是分析数据):

同时发送所有请求将提高网络电量效率。

结论

网页可以成为电池续航的好公民。

在 Web Inspector 中测量电池影响并降低这些成本非常重要。这样做可以改善用户体验和电池续航。

延长电池续航最直接的方法是最小化 CPU 使用率。新的 Web Inspector 提供了一个工具来实时监控这一点。

要实现出色的电池续航,目标是:

  • 在空闲时将 CPU 使用率降至零
  • 在用户互动期间最大限度地提升性能,以便快速回到空闲状态

如果您有任何问题,请随时联系Joseph PecoraroDevin Rousso,当然还有Jon Davis

注意:通过Web Inspector 参考文档了解更多关于 Web Inspector 的信息。