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

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

虽然这些新模式主要面向用户,但它们确实会产生一些影响,它们可能会影响网站的用户体验,因此,网站开发者需要格外注意。

这篇博文将介绍这些新模式的潜在影响,以及 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 最佳实践,他们的网站应该能够继续正常运行这些新模式。

不过,如果您的网站包含本博文中提到的任何一种做法,那么用户遇到的问题可能只有在启用这两种模式后才会加重。

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