Fetch Priority
Fetch Priority API
用于向浏览器指示资源的相对优先级。可以通过向 <img>
、<link>
、<script>
和 <iframe>
元素添加 fetchpriority
属性或通过 Fetch API
上的 priority
属性来配置优先级。
浏览器主要根据请求的类型和在文档标记中的位置来确定请求的优先级。
下面是一些示例和相应的代码,以说明不同资源的优先级:
- CSS 文件:在文档的
<head>
中请求的 CSS 文件通常被赋予最高优先级。
<head> <link rel="stylesheet" href="styles.css"> </head>
- JavaScript 文件:一般情况下,没有
async
或defer
属性的<script>
元素将被视为阻塞渲染资源
,并被赋予较高优先级。
<script src="script.js"></script>
- 图像:图像通常具有较低的默认优先级。我们可以通过添加
fetchpriority
属性来调整图像的优先级。
<img src="image.jpg" fetchpriority="high">
- 预加载资源:使用
<link rel="preload">
元素可以预先加载资源,但它不会直接影响资源的优先级。
<link rel="preload" href="resource.js" as="script">
除了一些特殊的资源,对于其他常规的资源,浏览器按照发现资源的顺序下载具有相同优先级
的资源。
fetchpriority
fetchpriority
属性可以用于提示浏览器增加
或降低
所请求资源的优先级。
该枚举属性可以有三个值:
high
: 该资源相对于其默认优先级更高low
: 该资源相对于其默认优先级更低auto
: 默认值
从Chromium
源码中,我们找到对应的定义。
举例说明
<img src="/789.jpg" alt="前端柒八九" fetchpriority="high" />
在上面的示例中,我们提示浏览器 <img>
的优先级比其默认优先级高。
对于 fetch
方法上的 priority
属性,同样支持相同的值。
fetch("/api/data.json", { priority: 'high' })
在上面的 fetch
请求中,我们向浏览器指示该 fetch
请求的优先级较其默认优先级更高。
Default priority
Fetch Priority API
可以增加
或降低
资源相对于其默认优先级的优先级。
例如,默认情况下,图片始终具有低优先级。将 fetchpriority="high"
分配给图片将把它们的优先级提升为高优先级。
另一方面,渲染阻塞的样式表
默认情况下具有最高优先级。将其分配为 fetchpriority="low"
将把其优先级降低为高优先级,而不是低优先级。
fetchpriority
用于相对于默认值调整资源的优先级,而不是显式设置其值。
在 Chromium
的资源优先级文档中记录了 Fetch Priority
对资源优先级的影响,包括不同的资源类型,它们的默认优先级(◉),以及使用 fetchpriority="high"
(⬆)和 fetchpriority="low"
(⬇)时的结果优先级。
- 使用
"as"
进行preload
或使用"type"
进行fetch
的操作将使用它们请求的类型的优先级,除非另有说明(比如字体)。
- 例如,使用
"preload as=stylesheet"
将使用最高优先级。如果没有指定"as"
,它们将表现得像XHR(XMLHttpRequest
)。
"Early"
指的是在请求任何非预加载的图像之前进行的请求("late"指的是之后)。- 当CSS的
媒体类型
不匹配时,预加载扫描器不会获取该CSS,而只有当主解析器到达时才会处理它,这通常意味着它将在非常晚的时候被获取,并且具有"late"
优先级。
优先级变化
图像始终以低优先级开始。如果在布局过程中发现图像在视口内,则优先级将提升为高优先级
,尽管这可能发生在加载过程中的相当晚的阶段。
位于页面底部并阻塞的脚本为中等优先级
。但是,如果主HTML解析器到达并被阻塞,优先级将提升为高优先级。(前面我们讲过,js
是解析器阻断资源
)
网络堆栈优先级名称
顺便说一嘴,在Chrome
中Network
的DevTool
中也会显示资源优先级。
Chrome
网络堆栈中显示的资源优先级名称与Chromium
中的Blink
中有些不同。但是,它们在自己的规则范围中,是能正确表达各个资源之间的优先级关系的。
完整的映射如下:
Chrome网络堆栈优先级名称 | Chrome优先级名称 |
IDLE | Lowest |
LOWEST | Low |
LOW | Medium |
MEDIUM | High |
HIGHEST | Highest |
紧凑模式(Tight mode)
在前面的前置知识中我们已经讲过何为{紧凑模式|Tight mode},并且还将其与{空闲模式|Idle mode}进行了对比。这里就不在赘述了。
在上面的瀑布图中,您可以看到资源 image-1.jpg
直到 style-2.css
完成下载后才开始下载,即使它已经被解析器探知。此时,只剩下一个正在处理的资源 - script.js
,所以浏览器开始下载低优先级的图片。
一旦所有位于 <head>
中的阻塞脚本
被下载并执行完成(带有 async
或 defer
的脚本不会阻塞渲染),初始阶段就完成了。即使有超过两个同时进行的请求,浏览器现在可以根据资源的优先级和在标记中的顺序继续下载任何剩余的资源。
在上面的图表中,一旦渲染阻塞的 JavaScript
被下载并执行(粉色条),浏览器开始下载图片,即使两个 CSS
文件仍在进行中。黄色的垂直条表示 DOM
可交互(即 readystatechange
事件被触发)的时间点。
案例分析
preconnet
如果图片位于不同的域名
上,浏览器在下载文件之前需要打开到该域名的连接。
这在 WebPageTest
的图表中显示为绿色
、橙色
和洋红色
的条形图,表示在下载之前的预连接过程。
我们可以使用 preconnect
资源提示来提前开始下载图片。
在上面的图表中,在初始阶段之前,浏览器打开了与 cdn.glitch.global
域的连接,这使得浏览器能够开始下载文件。一旦浏览器退出初始阶段(黄色垂直线
),它立即开始下载图片,从而节省了约 350 毫秒的时间。
preload
preload
指令允许你向浏览器提供关于“晚发现”
(late-discovered
)的关键资源的信息。这对于在样式表或脚本中加载的资源特别有用,例如背景图片
或字体
。
在我们的示例中,图片在标记中声明并且早早被发现,因此 preload
的效果很小。(效果有,但是不多)
在上面的图表中,我们用以下内容替代了 preconnect
:
<link rel="preload" as="image" href="https://cdn.glitch.global/.../image-1.jpg" />
尽管使用了 preload
,但图片仍然要等到同时进行的请求少于两个时才开始下载。
预加载资源类型
这里在额外说一些,关于哪些资源可以使用prelaod
。
fetchpriority
既然perlaod
在有些场景中效果不是很好,那么我们可以另谋出路。
我们可以使用 Fetch Priority
来向浏览器指示 image-1.jpg
的优先级比默认优先级更高,使用以下方式:
<img src="https://cdn.glitch.global/.../image-1.jpg" fetchpriority="high" alt="" />
这将把图片的初始优先级从低优先级提升到高优先级,使得图片可以在初始阶段被加载。
上面的瀑布图显示了在初始阶段与其他关键资源并行加载的 image-1.jpg
。这给我们带来了迄今为止最大的改进。
将 preload 和 fetchpriority 合并
到目前为止,Fetch Priority
只在基于 Chromium
的浏览器上受支持,然而,它在不支持识别 fetchpriority
属性的浏览器上会有优雅的失败处理。这使得我们可以将 preload
指令与 Fetch Priority
结合使用。
<link rel="preload" as="image" fetchpriority="high" href="https://cdn.glitch.global/.../image-1.jpg" />
支持 Fetch Priority
的浏览器将使用分配的 fetchpriority
进行预加载资源,而不支持的浏览器将使用 preload
指令进行预加载。
上面的图表显示了与之前包含在 <img>
元素上的 fetchpriority
属性的图表类似的结果。这种方法的优点在于统一了在支持 Fetch Priority
和不支持的浏览器上优先处理资源的方法。
fetchpriority 的好处
fetchpriority
的好处是指资源被发现的时间与开始下载的时间之间的差异。我将其称为机会
。因此,如果资源早早被发现,但浏览器开始下载它的时间较晚,那么机会就更大。
如果图像来自不同的域名,还可以将将建立连接的时间
包括在机会中。
总结
由于篇幅有限,关于LCP
的内容,这里先不展开,我们会单独出一篇文章。
- 将 LCP 图像托管在与 HTML 文档相同的域上。如果无法实现,请使用
preconnect
提前打开连接。 - LCP 图像应包含在文档标记中。如果无法实现,请使用
preload
告知浏览器在请求前下载图像。 - 尽量避免阻塞资源。如果 LCP 图像以低优先级下载,可以使用
fetchpriority
提示浏览器提前下载图像。
后记
分享是一种态度。
参考资料:
全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。