HTML性能优化-Prerender2.0机制解读
一、前言
日志是一种按照时间顺序Prerender(预渲染),是用户在打开网页之前提前将网页中资源加载并执行解析渲染工作,使网页真正被打开时以最快的速度呈现出来,理想状态下打开已预渲染的页面几乎是即时展现的。
<link rel="prerender" href="/next-page/">丨1.1 多页面架构(MPArch)
二、Prerender2.0使用及效果
GEEK TALK
丨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>
当前已经由NoState Prefetch机制使用,若强制改为Prerender机制,将不符合已使用此API站点的预期(网站并不想对使用此API的URL进行预渲染),且消耗资源大幅度增加,导致网站崩溃的风险。
规则可塑性较差,部分要求无法通过此规则限制,如Speculation Rules API中的requires参数含义难以在此规则中体现,且无法同时对多个站点预处理。
由于Speculation Rules API的灵活性较好,Chromium预言此API将逐步替代规则,成为开发者使用较多的API。
当activationStart大于0时便表示prerender页面复用成功。
监听'prerenderingchange'事件。
// 方式1let activationStart = performance.getEntriesByType('navigation')[0].activationStart;// 方式2let wasActivated = false;document.addEventListener('prerenderingchange', (event) => {wasActivated = true;});
丨2.2 使用效果
三、实现流程(基于M97)
丨3.1 解析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 页面加载流程
执行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,以展示给用户。
四、应用场景
GEEK TALK
丨4.1 Chromium
当置信度>50%(图中黄色),Chromium会发起预链接
当置信度>80%(图中绿色),Chromium会发起预渲染
丨4.2 开发者
对于明确站点中的某些页面是大部分用户会浏览的,便可对这些站点进行预渲染,此场景可通过静态方式将预渲染API写入HTML中。
也可针对不同用户使用不同策略,根据用户行为通过JS动态插入需要预渲染API。
五、总结
GEEK TALK
END
[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