开发者需了解关于 Chrome 的内存模式和节能模式的须知事项

Chrome 108 引入了两种新模式:省内存模式和节能模式,以便用户更好地控制 Chrome 使用其系统资源的方式。

虽然这些新模式主要面向用户,但 Web 开发者需要注意一些重要影响,因为这些影响可能会影响您网站的用户体验。

本文将介绍这些新模式的潜在影响,以及 Web 开发者可以采取哪些措施来确保提供尽可能出色的体验。

省内存模式

启用省内存模式后,Chrome 会主动舍弃在后台闲置了一段时间的标签页。这样可以为处于活动状态的标签页以及可能正在运行的其他应用释放内存。用户可以指示 Chrome 不要舍弃特定网站的标签页;不过,这是一种用户偏好设置,您作为开发者无法控制。

舍弃标签页后,其标题和图标仍会显示在标签页栏中,但页面本身会消失,就像该标签页已正常关闭一样。如果用户再次访问该标签页,页面将自动重新加载。

对于纯内容页面,舍弃并重新加载标签页可能不会影响用户体验,但对于包含复杂用户体验流程的富媒体互动型网站,如果网站无法将页面恢复到用户离开时的位置,那么在用户体验流程的中途重新加载可能会让用户感到非常沮丧。

丢弃标签页以节省内存是 Chrome 多年来一直在做的事,但只有在系统内存压力较大的情况下才会执行此操作。由于这种情况相对较少发生,Web 开发者可能并未意识到其存在。

从 Chrome 108 开始,标签页舍弃将变得更加常见,因此网站必须能够妥善处理这些情况。

处理标签页舍弃的最佳实践

标签页舍弃对 Web 开发者来说并不是一个新挑战。用户有可能在完成任务之前有意或无意地重新加载页面。因此,网站始终需要存储用户状态,以便在用户离开后再次访问时恢复该状态。

最重要的考虑因素不是是否存储用户状态,而是何时存储。这一点至关重要,因为在丢弃标签页时不会触发任何事件,因此开发者无法对此做出响应。相反,开发者需要预见这种可能性并提前做好准备。

存储用户状态的最佳时机如下:

  • 在状态发生变化时定期执行。
  • 每当标签页进入后台时(visibilitychange 事件)。

存储状态最糟糕的时机如下:

  • beforeunload 事件回调中。
  • unload 事件回调中。

这时存储状态是最糟糕的选择,因为这些事件完全不可靠,在许多情况下都不会触发,包括在丢弃标签页时。

您可以参阅页面生命周期事件图,了解在页面被舍弃时触发的事件。如图所示,标签页可以从“已隐藏”状态转换为“已舍弃”状态,而无需触发任何事件。

Page Lifecycle API 状态和事件流程。直观呈现本文档中介绍的状态和事件流程。

事实上,每当页面处于“隐藏”状态时,都无法保证在浏览器舍弃页面或用户终止页面之前,系统会触发任何其他事件。因此,请务必始终在 visibilitychange 事件中存储所有未保存的用户状态,因为您可能不会再有机会了。

以下代码概述了一些示例逻辑,用于在当前用户状态每次发生变化时将其加入队列以进行持久化,或者在用户将标签页置于后台或导航离开时立即进行持久化:

let state = {};
let hasUnstoredState = false;

function storeState() {
  if (hasUnstoredState) {
    // Store `state` to localStorage or IndexedDB...
  }
  hasUnstoredState = false;
}

export function updateState(newState) {
  state = newState;
  hasUnstoredState = true;
  requestIdleCallback(storeState);
}

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    storeState();
  }
});

检测到标签页被舍弃

如前所述,无法检测标签页即将被舍弃,但可以检测在用户返回标签页并重新加载页面后标签页是否已被舍弃。在这些情况下,document.wasDiscarded 属性将为 true。

if (document.wasDiscarded) {
  // The page was reloaded after a discard.
} else {
  // The page was not reloaded after a discard.
}

如果您想了解用户遇到此类情况的频率,可以配置分析工具来捕获此类信息。

例如,在 Google Analytics 中,您可以配置自定义事件参数,以确定网页浏览中有多少百分比是由于标签页舍弃而产生的:

gtag('config', 'G-XXXXXXXXXX', {
  was_discarded: document.wasDiscarded,
});

如果您是分析服务提供商,不妨考虑将此维度默认添加到您的产品。

在省内存模式模式下测试您的网站

您可以通过以下方式测试网页如何处理被舍弃的情况:加载网页,然后在单独的标签页或窗口中访问 chrome://discards

chrome://discards 界面中,您可以找到要从列表中舍弃的标签页,然后点击操作列中的紧急舍弃

chrome://discards 界面的屏幕截图,显示了指向“已舍弃”标签页的链接的位置

此操作会舍弃该标签页,让您可以重新访问该标签页,并验证该网页是否已重新加载到其离开时的状态。

请注意,目前无法通过 webdriver 或 puppeteer 等测试工具自动舍弃标签页;不过,由于标签页舍弃和恢复与页面重新加载几乎完全相同,因此如果您测试在用户体验流程的中途重新加载后用户状态是否会恢复,那么结果可能也适用于舍弃/恢复操作。这两者之间的主要区别在于,在丢弃标签页时,系统不会触发 beforeunloadpagehideunload 事件,因此,只要您不依赖这些事件来保留用户状态,就可以使用重新加载来测试丢弃/恢复行为。

节能模式

启用节能模式后,Chrome 会降低显示刷新频率(这会影响滚动和动画保真度以及视频帧速率),从而节省电池电量。

通常,开发者无需执行任何操作即可支持省电模式。启用此模式后,用于动画转场效果requestAnimationFrame() 的 CSS 和 JavaScript API 会自动调整以适应显示刷新率的任何变化。

此模式可能会出现问题的主要场景是,您的网站使用基于 JavaScript 的动画,假定所有用户的刷新率都是特定值。

例如,如果您的网站使用 requestAnimationFrame() 循环,并假设回调之间会经过 16.67 毫秒的时间,那么在启用省电模式后,动画的运行速度会变慢一倍。

请注意,对于开发者来说,假定所有用户的默认刷新率为 60 Hz 一直都是个问题,因为目前许多设备并非如此。

衡量显示屏刷新率

没有专门用于测量显示刷新率的 Web API,通常不建议尝试使用当前 API 执行此操作。

开发者对现有 API 能做的最好的事情就是比较连续 requestAnimationFrame() 回调之间的时间戳。虽然在大多数情况下,此方法可以估算出给定时间点的刷新率,但当刷新率发生变化时,系统不会通知您。为此,您必须持续运行 requestAnimationFrame() 轮询,这会抵消为用户节省电量或延长电池续航时间的目标。

在节能模式下测试您的网站

如需在节能模式下测试您的网站,一种方法是在 Chrome 的设置中启用该模式,并将其配置为在设备拔下电源时运行。

如果您没有可以拔下电源线的设备,也可以按照以下步骤手动启用此模式:

  1. 启用 chrome://flags/#battery-saver-mode-available 标志。
  2. 访问 chrome://discards,然后点击切换省电模式链接(重要提示:需要启用 #battery-saver-mode-available 标志,该链接才能正常运行)。

chrome://discards 界面的屏幕截图,显示了启用节能模式的链接的位置

启用该功能后,您可以与网站互动,并验证一切是否正常显示:例如,动画和转场效果是否以所需的速度运行。

摘要

虽然 Chrome 的省内存模式和节能模式主要面向用户,但它们确实会对开发者产生影响,因为如果处理不当,可能会对您网站的访问体验产生负面影响。

一般而言,这些新模式的设计遵循了现有的开发者最佳实践。如果开发者一直遵循长期以来的 Web 最佳实践,他们的网站应该能够继续正常运行这些新模式。

不过,如果您的网站存在本文中提及的任何做法,用户可能会遇到问题,而启用这两种模式只会增加问题。

与往常一样,确认网站是否提供出色体验的最佳方法是,使用符合用户条件的条件测试您的网站。