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