HTML性能优化-Prerender2.0机制解读
一. 前言
Prerender(预渲染),是用户在打开网页之前提前将网页中资源加载并执行解析渲染工作,使网页真正被打开时以最快的速度呈现出来,理想状态下打开已预渲染的页面几乎是即时展现的。
<link rel="prerender" href="/next-page/">
丨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模型。
可见Prerender机制在使用单WebContents模型相对于多WebContents模型在内存的使用上有着明显的优势,这应该是Prerender2.0比Prerender1.0轻便之处。
二. Prerender2.0使用及效果
丨2.1 能力使用
HTMLScriptElement.supports('speculationrules')
<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>
参数 | 含义 | 备注 |
prerender | 使用预渲染机制 | |
prefetch | 使用预加载机制,仅预加载主文档 | 内部使用SimpleURLLoader实现主文档的预加载 |
prefetch_with_subresources | 使用预加载机制,预加载主文档+关键子资源。功能效果类似于NSP | 内部使用SimpleURLLoader实现主文档的预加载 |
prefetch_with_subresources | 使用预加载机制,预加载主文档+关键子资源。功能效果类似于NSP | 内部使用SimpleURLLoader实现主文档的预加载 |
requires | 在确保客户端IP对服务端不可见时,可预加载跨域资源 | value只能为"anonymous-client-ip-when-cross-origin",且只支持key为prefetch和prefetch_with_subresources的场景中使用 |
<link rel=prerender>当前已经由NoState Prefetch机制使用,若强制改为Prerender机制,将不符合已使用此API站点的预期(网站并不想对使用此API的URL进行预渲染),且消耗资源大幅度增加,导致网站崩溃的风险。 <link>规则可塑性较差,部分要求无法通过此规则限制,如Speculation Rules API中的requires参数含义难以在此规则中体现,且无法同时对多个站点预处理。 由于Speculation Rules API的灵活性较好,Chromium预言此API将逐步替代<link>规则,成为开发者使用较多的API。
当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
丨3.2 预渲染流程
在Browser线程中判断跳转页面是否需要网络层处理,若需要网络层处理,则走网络请求逻辑,实现资源请求并返回主文档首包(也有跳转不需要网络层处理,比如同Document跳转)。无论是否走网络层逻辑,最终都会走到CommitNavigation方法,CommitNavigation就是Browser线程向Render线程提交跳转的入口。 CommitNavigation至Render线程后将创建Document和DocumentLoader等对象,而DocumentLoader是用于处理主文档内容加载完成后回调通知。待收到主文档数据后开始解析、渲染流程。
丨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,以展示给用户。
四. 应用场景
四. 应用场景
由于预渲染页面对于设备的资源消耗较大,是个需要谨慎使用的机制能力,若肆无忌惮的使用此能力,不仅无法提高用户的浏览体验,还会耗尽用户的宝贵资源,可能带来卡顿、崩溃等负向影响。Chromium推荐用法中表示当用户加载某些页面的可能性很高时才推荐使用Prerender机制,此时可将Prerender机制带来的正向收益最大化。
丨4.1 Chromium
Chromium将预测技术与Prerender2.0机制结合使用,利用预测技术提高预渲染页面的准确性。通过chrome://predictors页面可看出Chromium对用户行为的预测,如下图。
绿色表示有足够信心触发预渲染。以上示例可看出,当用户在输入框中输入"b"/"ba"/"bai"字符后chromium将对"https://www.baidu.com/"站点发起预渲染,因为经过多次统计有足够的信心认为用户将进入目标站点。
当置信度>50%(图中黄色),Chromium会发起预链接
当置信度>80%(图中绿色),Chromium会发起预渲染
同时Chromium会将预测的结果呈现在Sug选项栏中,辅助用户进入目标站点。
丨4.2 开发者
对于搜索类浏览器可参考Chromium思路,定制合适的预测器并结合Prerender2.0机制使用,用于提升搜索结果页的上屏性能,优化用户体验。
对于明确站点中的某些页面是大部分用户会浏览的,便可对这些站点进行预渲染,此场景可通过静态方式将预渲染API写入HTML中。 也可针对不同用户使用不同策略,根据用户行为通过JS动态插入需要预渲染API。
网站衡量使用预渲染能力是否得当,可增加指标查看预渲染效果。主要看两个指标,一个是发起预渲染页面数量,另一个是用户真实加载已预渲染的页面数量(上文中提及的获取方式),两个指标的对比可估算出命中率。网站可调整预渲染策略以保持高命中率。
五. 总结
五. 总结
本文主要介绍了Prerender机制的发展过程和现状,并对Prerender2.0技术进行介绍。其中重点介绍了Prerender2.0技术的使用、实现流程和应用场景。百度APP是基于Chromium M97,此版本中Prerender2.0机制还在初级阶段,目前为止Chromium还在对Prerender2.0技术进行完善,故文档中内容可能和最新方案有些许差异。后期我们将持续关注Prerender2.0技术发展,发掘其应用于业务的可行场景,持续优化页面上屏性能,提升用户体验。
六. 参考文档
六. 参考文档
[1] Prerender开发者文档:https://developer.chrome.com/blog/prerender-pages/
[2] Prerender官方文档:https://docs.google.com/document/d/1P2VKCLpmnNm_cRAjUeE-bqLL0bslL_zKqiNeCzNom_w/edit
[3] 多页面架构文档:https://docs.google.com/document/d/1NginQ8k0w3znuwTiJ5qjYmBKgZDekvEPC22q0I4swxQ/edit#heading=h.w1qo2n6sr8wn