共计 5589 个字符,预计需要花费 14 分钟才能阅读完成。
一、前言
日志是一种依照工夫程序 Prerender(预渲染),是用户在关上网页之前提前将网页中资源加载并执行解析渲染工作,使网页真正被关上时以最快的速度出现进去,现实状态下关上已预渲染的页面简直是即时展示的。
Chromium 在过来曾经反对过 Prerender(Prerender1.0,应用工夫在 2011~2018),其 API 应用办法如下,针对单个链接做预渲染,因为此能力的应用须要耗费较高的设施资源,实用性不太大,导致没有失去广泛应用,故逐步被弃用。而此 API 后续利用在 NoState Prefetch 中,NSP 机制只对指标网页中的要害资源进行预加载,并不会执行后续的渲染工作,也不会执行 JS,即通过缩小资源加载耗时以进步页面性能,但做不到预渲染及时展示页面的成果。
<link rel="prerender" href="/next-page/">
Chromium 从 M94 开始将 Prerender 机制(Prerender2.0)从新引入。Prerender2.0 是全新的预渲染技术,此版本着重于进步预渲染页面的准确性并缩小执行预渲染所需的设施资源量,缩短页面加载工夫、改善用户体验并升高设施功耗。Prerender2.0 比 Prerender1.0 更加灵便、智能和轻便,能够更无效地进步页面加载速度。
丨 1.1 多页面架构(MPArch)
MPArch(Multiple Page Architecture)多页面架构,此架构中采纳了单 WebContents 模型,实现一个 WebContent 中治理多个 page(可见 / 不可见),WebContents 和 Page 之间不是一一对应关系。单 WebContents 模型十分实用 BF Cache 和 Prerender 等须要在同一选项卡中反对多个页面的性能。
Prerender2.0 建设在 MPArch 之上,即应用了单 WebContents 多 page 模型。而 Prerender1.0 时还没有反对此能力,而是每预渲染一个页面均创立新的 WebContent,每个 WebContent 仅对应一个预渲染页面,即 Prerender1.0 采纳的是多 WebContents 模型。
图片来源于 chromium
可见 Prerender 机制在应用单 WebContents 模型绝对于多 WebContents 模型在内存的应用上有着显著的劣势,这应该是 Prerender2.0 比 Prerender1.0 轻便之处。
二、Prerender2.0 应用及成果
丨 2.1 能力应用
应用 Prerender2.0 机制须要应用新增的 Speculation Rules API(https://github.com/WICG/nav-s…),此 API 可同时反对触发 Prefetch、NSP、Prerender 机制。
查看浏览器是否反对此 API。
HTMLScriptElement.supports('speculationrules')
API 应用示例如下:
<script type="speculationrules">
{
"prerender": [
{"source": "list",
"urls": ["next.html", "./PrefetchTestNew.html"]}
],
"prefetch": [
{"source": "list",
"urls": ["next.html"],
"requires": ["anonymous-client-ip-when-cross-origin"]}
],
"prefetch_with_subresources": [
{"source": "list",
"urls": ["next.html"],
"requires": ["anonymous-client-ip-when-cross-origin"]}
]
}
</script>
API 中要害
未持续应用 <link rel=prerender> 的起因如下:
- 以后曾经由 NoState Prefetch 机制应用,若强制改为 Prerender 机制,将不合乎已应用此 API 站点的预期(网站并不想对应用此 API 的 URL 进行预渲染),且耗费资源大幅度减少,导致网站解体的危险。
- 规定可塑性较差,局部要求无奈通过此规定限度,如 Speculation Rules API 中的 requires 参数含意难以在此规定中体现,且无奈同时对多个站点预处理。
- 因为 Speculation Rules API 的灵活性较好,Chromium 预言此 API 将逐渐代替规定,成为开发者应用较多的 API。
应用了以上 API 对页面发动 Prerender 后,如何晓得用户关上了已 Prerender 的页面,获取形式如下:
- 当 activationStart 大于 0 时便示意 prerender 页面复用胜利。
- 监听 ’prerenderingchange’ 事件。
// 形式 1
let activationStart = performance.getEntriesByType('navigation')[0].activationStart;
// 形式 2
let wasActivated = false;
document.addEventListener('prerenderingchange', (event) => {wasActivated = true;});
丨 2.2 应用成果
应用 Chromium 提供的视频示例,不应用 Prerender 能力能够显著的看到页面中内容从 0 到 1 展现的过程,而应用 Prerender 后页面简直是即时展现的。成果比照非常明显。
三、实现流程(基于 M97)
丨 3.1 解析 Speculation Rules API
解析到 HTML 中的 Speculation Rules API 后的流程如下:
流程如下:
- 解析 HTML 中蕴含 ScriptType 为 kSpeculationRules 的 JS 内容后,开始对原数据进行 JSON 解析,匹配出无效内容,包含 SpeculationAction(kPrefetch、kPrefetchWithSubresources、kPrerender)、SpeculationRule(urls、requires\_anonymous\_client\_ip\_when\_cross\_origin);
- 若 SpeculationAction 为 kPrerender 时,开始判断是否合乎发动 prerender 的条件(判断条件如下),若合乎则开始执行 StartPrerendering;
- 发动 prerender 的页面需可见
- 以后设施平台的内存空间短缺(限度低端机开启 Prerender 机制)
- 不容许发动跨域 prerender(即 prerender URL 需和发动 prerender 的页面同源)(Chromium 示意预计于 M109 反对跨域 prerender)
- 不能反复发动 prerender
-
一个页面中不能发动多个 prerender
PrerenderHost 是在 Browser 侧治理着单个预渲染页面的类,其对应着 PrerenderHost::PageHolder,在 PageHolder 中创立预渲染的 FrameTree,而 PrerenderHostRegistry 治理所有的 PrerenderHost。可见一个 WebContents 对应多个 FrameTree。
丨 3.2 预渲染流程
每个预渲染页面均以 PrerenderHost::StartPrerendering() 开始,而后执行到 NavigationRequset 中 BeginNavigation 办法,前面的逻辑均和失常页面加载流程统一。
- 在 Browser 线程中判断跳转页面是否须要网络层解决,若须要网络层解决,则走网络申请逻辑,实现资源申请并返回主文档首包(也有跳转不须要网络层解决,比方同 Document 跳转)。无论是否走网络层逻辑,最终都会走到 CommitNavigation 办法,CommitNavigation 就是 Browser 线程向 Render 线程提交跳转的入口。
- CommitNavigation 至 Render 线程后将创立 Document 和 DocumentLoader 等对象,而 DocumentLoader 是用于解决主文档内容加载实现后回调告诉。待收到主文档数据后开始解析、渲染流程。
预渲染实现后的页面将以 FrameTree 的构造存在,FrameTree 由 PrerenderHost 持有。每个预渲染页面对应一个 PrerenderHost 对象,所有的 PrerenderHost 存储在 Map 中以 frame\_tree\_node\_id 作为 key,Map 以成员变量的模式保留在 PrerenderHostRegistry 中。此时预渲染的 Page 对于用户是不可见的。
丨 3.3 页面加载流程
点击链接进入已预渲染的页面,仍旧是执行到 NavigationRequset 中 BeginNavigation 办法。
- 执行 BeginNavigation 办法时会到 PrerenderHostRegistry 类中寄存 PrerenderHost 的 Map 中查找是否有符合要求的 PrerenderHost 对象,匹配规定是查看以后 navigationRequest 中的 URL 与 PrerenderHost 中的 URL 是否统一,统一则匹配胜利,同时返回 frame\_tree\_node\_id。找到符合条件的 frame\_tree\_node\_id 后开始操作将 prerenderPage 的状态切换为 active。
- 后续仍旧须要至网络库中申请主文档首包,用于查看页面是否可用,并对申请头进行验证,确保可复用的预渲染页面与须要加载的页面的 RequestHeaders 和 ResponseHeaders 内容统一。
- 以上验证均通过后,便可执行 CommitNavigation,针对 BFCache 和 Prerender 页面都是先找到 stored\_page,并将 stored\_page 的状态切换为 active,以展现给用户。
找出符合条件的 stored\_page,将此页面展示进去,并将上个页面暗藏存储至 BFCache 中。如下图所示。
四、利用场景
因为预渲染页面对于设施的资源耗费较大,是个须要审慎应用的机制能力,若胡作非为的应用此能力,不仅无奈进步用户的浏览体验,还会耗尽用户的贵重资源,可能带来卡顿、解体等负向影响。Chromium 举荐用法中示意当用户加载某些页面的可能性很高时才举荐应用 Prerender 机制,此时可将 Prerender 机制带来的正向收益最大化。
丨 4.1 Chromium
Chromium 将预测技术与 Prerender2.0 机制联合应用,利用预测技术进步预渲染页面的准确性。通过 chrome://predictors 页面可看出 Chromium 对用户行为的预测,如下图。
绿色示意有足够信念触发预渲染。以上示例可看出,当用户在输入框中输出 ”b”/”ba”/”bai” 字符后 chromium 将对 ”https://www.baidu.com/” 站点发动预渲染,因为通过屡次统计有足够的信念认为用户将进入指标站点。
Chromium 会依据用户输出和抉择一直的更新预测后果。
- 当置信度 >50%(图中黄色),Chromium 会发动预链接
- 当置信度 >80%(图中绿色),Chromium 会发动预渲染
同时 Chromium 会将预测的后果出现在 Sug 选项栏中,辅助用户进入指标站点。
进入指标站点后通过 ”performance.getEntriesByType(‘navigation’)[0].activationStart” 查看页面是否通过预渲染出现的,依据 activationStart 大于 0 可确定此页面已预渲染胜利。
丨 4.2 开发者
对于搜寻类浏览器可参考 Chromium 思路,定制适合的预测器并联合 Prerender2.0 机制应用,用于晋升搜寻后果页的上屏性能,优化用户体验。
对于网站开发者而言,能够联合本身站点状况应用预渲染技术
- 对于明确站点中的某些页面是大部分用户会浏览的,便可对这些站点进行预渲染,此场景可通过动态形式将预渲染 API 写入 HTML 中。
- 也可针对不同用户应用不同策略,依据用户行为通过 JS 动静插入须要预渲染 API。
网站掂量应用预渲染能力是否切当,可减少指标查看预渲染成果。次要看两个指标,一个是发动预渲染页面数量,另一个是用户实在加载已预渲染的页面数量(上文中提及的获取形式),两个指标的比照可估算出命中率。网站可调整预渲染策略以放弃高命中率。
五、总结
本文次要介绍了 Prerender 机制的倒退过程和现状,并对 Prerender2.0 技术进行介绍。其中重点介绍了 Prerender2.0 技术的应用、实现流程和利用场景。百度 APP 是基于 Chromium M97,此版本中 Prerender2.0 机制还在初级阶段,目前为止 Chromium 还在对 Prerender2.0 技术进行欠缺,故文档中内容可能和最新计划有些许差别。前期咱们将继续关注 Prerender2.0 技术倒退,挖掘其利用于业务的可行场景,继续优化页面上屏性能,晋升用户体验。
——END——
参考资料:
[1] Prerender 开发者文档:
https://developer.chrome.com/…
[2] Prerender 官网文档:
https://docs.google.com/docum…\_cRAjUeE-bqLL0bslL\_zKqiNeCzNom\_w/edit
[3] 多页面架构文档:
https://docs.google.com/docum…
举荐浏览:
百度工程师浅谈分布式日志
百度工程师带你理解 Module Federation
巧用 Golang 泛型,简化代码编写
Go 语言 DDD 实战高级篇
Diffie-Hellman 密钥协商算法探索
贴吧低代码高性能规定引擎设计