关键渲染路径概念与优化方案

366 阅读3分钟

什么是关键渲染路径(Critical Rendering Path)

按照chrome的解释,关键渲染路径表示在页面初次加载时,哪些资源以高优先级展示。可以使用lighthouse检测,在Critical request chains下,可以看到页面渲染时的关键渲染路径:

image.png 减少链的长度,减少资源的下载大小,或推迟下载不必要的资源以提高页面负载。

Navigation Timing API

image.png

  • domLoading: 整个流程的开端, 浏览器开始解析(parse)第一个收到的html文档字节.

  • domInteractive: 表明浏览器完成了所有html和dom结构的解析,表示Dom准备就绪.

  • domContentLoaded: 标志着DOM已经准备完成并且不存在被javaScript阻塞的stylesheets - 意味着页面现在就可以构造渲染树(render tree),表示DOM和CSSOM准备就绪,如果没有js堵塞,会在domInteractive后立即执行.

    • 许多JavaScript框架在开始执行自己的逻辑之前等待此事件。因此,浏览器会捕获“EventStart”和“EventEnd”时间戳,以便我们跟踪执行时间。
  • domComplete: as the name implies, 所有的流程已经结束,并且所有的页面资源 (图片等.)都被加载完成标志着所有相关资源准备就绪.

  • loadEvent: 浏览器就在页面的最后一步,触发 onload事件.事件会触发额外的应用程序逻辑

一个计算页面各阶段事件的demo:

<!DOCTYPE html>  
<html>  
<head>  
<title>Critical Path: Measure</title>  
<meta name="viewport" content="width=device-width,initial-scale=1" />  
<link href="style.css" rel="stylesheet" />  
<script>  
function measureCRP() {  
var t = window.performance.timing,  
interactive = t.domInteractive - t.domLoading,  
dcl = t.domContentLoadedEventStart - t.domLoading,  
complete = t.domComplete - t.domLoading;  
var stats = document.createElement('p');  
stats.textContent =  
'interactive: ' +  
interactive +  
'ms, ' +  
'dcl: ' +  
dcl +  
'ms, complete: ' +  
complete +  
'ms';  
document.body.appendChild(stats);  
}  
</script>  
</head>  
<body onload="measureCRP()">  
<p>Hello <span>web performance</span> students!</p>  
<div><img src="awesome-photo.jpg" /></div>  
</body>  
</html>

关键路径优化

css方向优化

  • 把link放在document的首部:把css link放在首部可以在html parse的过程中,尽快的获取css资源,不被JavaScript阻塞
  • 避免使用css imports: 使用@imports会增长关键渲染路径,因为只有在解析到@import时,才会发起对应的css请求
  • 内联css,内联css无额外请求,可以将关键css(渲染页面必须的css)用内联的方式引入
  • 减少不必要的css: 比如媒体查询的css,可以在媒体条件触发时引入,首屏不需要的css可以不在关键路径引入

js方向优化

无论我们使用<script>标记还是内联JavaScript片段,您都希望两者的行为相同。在这两种情况下,浏览器都会暂停并执行脚本,然后才能处理文档的其余部分。然而,对于外部JavaScript文件,浏览器必须暂停以等待从磁盘、缓存或远程服务器获取脚本,这可能会给关键渲染路径增加数万毫秒的延迟。

默认情况下,所有JavaScript都是解析器阻塞。因为浏览器不知道脚本计划在页面上做什么,所以它假设最坏的情况并阻止解析器。向浏览器发出不需要在引用脚本的确切位置执行脚本的信号,允许浏览器继续构建DOM,并在脚本准备就绪时执行脚本;例如在从缓存或远程服务器获取文件之后。

  • 使用async和defer: 如果脚本无需等待页面解析,且无依赖独立运行,那么应使用 async。 如果脚本需要等待页面解析,且依赖于其它脚本,调用这些脚本时应使用 defer,将关联的脚本按所需顺序置于 HTML 中。(相关说明)
  • 避免js长任务
  • navigator.sendBeacon (感觉不像是减小首屏资源的方法)

参考

  1. developer.chrome.com/docs/lighth…
  2. web.dev/critical-re…