简介
NoState 预提取是 Chrome 中的一个新机制,可替代已废弃的预渲染流程,用于为 <link rel="prerender">
等功能提供支持。与预渲染类似,它会提前提取资源;但与预渲染不同的是,它不会提前执行 JavaScript 或渲染网页的任何部分。NoState 预提取的目标是比预渲染使用更少的内存,同时仍能缩短网页加载时间。
NoState 预提取不是 API,而是 Chrome 用于实现各种 API 和功能的机制。Resource Hints API 以及 Chrome 地址栏对网页的预加载都使用 NoState 预加载实现。如果您使用的是 Chrome 63 或更高版本,您的浏览器已经在针对 <link rel="prerender">
等功能使用 NoState 预提取。
本文介绍了 NoStatePrefetch 的工作原理、引入该功能的动机,以及使用 Chrome 的直方图查看其使用情况统计信息的说明。
设计初衷
引入 NoState 预提取有两个主要原因:
减少内存用量
NoState 预取仅使用约 45 MiB 的内存。维护预加载扫描器是 NoState 预提取的主要内存开销,并且在不同的使用情形中,此开销保持相对不变。增加提取的大小或数量不会对 NoState 预提取所消耗的内存量产生显著影响。
相比之下,预渲染通常会消耗 100 MiB 的内存,并且内存用量上限为 150 MiB。由于内存消耗较高,因此不适用于低端(即 RAM 小于等于 512MB)设备。因此,Chrome 不会在低端设备上进行预渲染,而是会预连接。
简化对新 Web 平台功能的支持
在预渲染期间,应用不应执行任何面向用户的操作(例如播放音乐或视频)或有状态的操作(例如更改会话或本地存储)。不过,在呈现页面时,要想防止这些操作发生,可能很难且很复杂。NoState 预提取仅会提前提取资源:不会执行代码或渲染网页。这样,您就可以更轻松地防止发生面向用户的操作和有状态的操作。
实现
以下步骤介绍了 NoState 预提取的工作原理。
系统不会触发 NoStatePrefetch。
预渲染资源提示 (即
<link rel="prerender">
) 和某些 Chrome 功能会触发 NoState 预提取,前提是满足以下两个条件:a) 用户使用的是高端设备,b) 用户使用的是 Wi-Fi 网络。为 NoState 预提取创建了新的专用渲染程序。
在 Chrome 中,“渲染程序”是一个进程,负责获取 HTML 文档、对其进行解析、构建其渲染树,并将结果绘制到屏幕上。Chrome 中的每个标签页以及每个 NoState 预提取进程都有自己的渲染程序来提供隔离。这有助于最大限度地减少错误(例如标签页崩溃)的影响,并防止恶意代码访问其他标签页或系统的其他部分。
系统会提取使用 NoState 预提取加载的资源。然后,HTMLPreloadScanner 会扫描此资源,以发现需要提取的任何子资源。 如果主资源或其任何子资源具有已注册的服务工件,这些请求将通过相应的服务工件。
NoState 预提取仅支持 GET HTTP 方法;它不会提取需要使用其他 HTTP 方法的任何子资源。此外,它不会提取任何需要用户操作的资源(例如身份验证弹出式窗口、SSL 客户端证书或手动替换项)。
提取的子资源将使用“IDLE”网络优先级进行提取。
“IDLE”网络优先级是 Chrome 中可用的最低网络优先级。
NoState 预提取检索的所有资源都会根据其缓存标头进行缓存。
NoState 预提取功能会缓存除包含
no-store
Cache-Control 标头的资源之外的所有资源。如果资源包含Vary
响应标头、no-cache
Cache-Control 标头,或者资源已超过 5 分钟,则系统会在使用前重新验证资源。在所有子资源加载完毕后,系统会终止渲染程序。
如果子资源超时,渲染程序将在 30 秒后终止。
除了更新 Cookie 存储区和本地 DNS 缓存之外,浏览器不会进行任何状态修改。 请务必注意这一点,因为这是“NoState 预提取”中的“NoState”。
在“正常”网页加载流程的此时刻,浏览器可能会执行会修改浏览器状态的操作:例如,执行 JavaScript、更改
sessionStorage
或localStorage
、播放音乐或视频、使用 History API 或提示用户。在 NoState 预提取中发生的唯一状态修改是响应到达时更新 DNS 缓存,以及响应包含Set-Cookie
标头时更新 Cookie 存储区。当需要资源时,系统会将其加载到浏览器窗口中。
不过,与预渲染的网页不同,该网页不会立即显示,而需要由浏览器进行渲染。浏览器不会重复使用用于 NoState 预提取的渲染程序,而是会使用新的渲染程序。不预渲染页面可以减少 NoStatePrefetch 的内存用量,但也会降低其对网页加载时间的可能影响。
如果网页有 Service Worker,此网页加载将再次通过 Service Worker。
如果 NoState 预提取在需要页面时尚未完成提取子资源,浏览器将从 NoState 预提取中断的地方继续页面加载过程。浏览器仍需要提取资源,但所需的资源数量不会像未启动 NoState 预提取时那么多。
对 Web 版 Google Analytics 的影响
使用 NoState 预提取加载的网页由网站分析工具注册的时间略有不同,具体取决于工具是在客户端还是在服务器端收集数据。
客户端分析脚本会在向用户显示网页时注册网页浏览。这些脚本依赖于 JavaScript 的执行,而 NoState 预提取不会执行任何 JavaScript。
服务器端分析工具会在处理请求时注册指标。对于通过 NoState 预提取加载的资源,在处理请求和客户端实际使用响应(如果有)之间可能会有相当长的时间间隔。从 Chrome 69 开始,无状态预提取会向所有请求添加标头 Purpose: Prefetch
,以便将其与正常浏览区分开来。
去看看
NoStatePrefetch 已于 2017 年 12 月在 Chrome 63 中发布。目前,它用于:
- 实现
prerender
资源提示 - 提取 Google 搜索结果中的第一个结果
- 提取 Chrome 地址栏预测您接下来可能会访问的网页
您可以使用 Chrome 内部信息查看自己是如何使用 NoStatePrefetch 的。
如需查看已使用 NoState 预提取加载的网站列表,请前往 chrome://net-internals/#prerender。
如需查看 NoState 预提取用法统计信息,请前往 chrome://histograms 并搜索“NoStatePrefetch”。NoState 预提取有三个不同的直方图,每个 NoState 预提取用例对应一个直方图:
- “NoStatePrefetch”(预渲染资源提示的使用情况统计数据)
- “gws_NoStatePrefetch”(Google 搜索结果页的使用情况统计信息)
- “omnibox_NoStatePrefetch”(Chrome 地址栏的使用情况统计信息)