油管、BBC 都在用的优化技术:fetchPriority
看了看油管的网站,发现它们用了这个属性,解决了之前怎么设置资源优先级的困扰。
简介
我们都知道,在浏览器解析网页并开始发现和下载资源(如图片、脚本或CSS)时,它会为这些资源分配一个获取优先级,以尝试以最优顺序下载资源。这些优先级可以取决于资源的类型以及其在文档中的位置。例如,在视口内的图片可能具有High
的优先级,在<head>
中的<link>
元素加载的CSS可能具有Very High
的优先级。浏览器在分配优先级方面表现得相当不错,但在某些情况下可能不是最优的。
Fetch Priority 可以在以下几个关键领域发挥作用:
提高图片LCP的优先级: 在 img 元素上指定 fetchpriority="high"
,可以使 LCP 尽早的触发。
使用更好的语义来增加异步脚本的优先级: 这比通常使用的 <link rel="preload">
更有效。
降低后加载脚本的优先级: 这样可以更好地与图片进行顺序加载。
以前,我们会使用 preload
和 preconnect
对资源优先级有一些影响, 但是这种影响时有限的。Fetch Priority 是 Resource Hints 的补充,但是理解它们的使用位置很重要。
Preload 可以让你告诉浏览器你想要在关键资源被自然发现之前就加载它们。这对于不容易发现的资源特别有用,例如样式表中包含的字体、背景图或从 script 加载的资源。
Fetch Priority 是一种基于标记的信号(设置 fetchpriority 属性),可以用它告诉特定资源的相对优先级。您还可以通过 JavaScript 和 Fetch API 使用这些提示,Fetch API 是通过设置 priority
属性。Fetch Priority 还可以与 preload 配合使用。比如,在样式表中包含的 LCP 图片即使使用了预加载,但是它的优先级仍然很低。如果它被其他早期低优先级资源推迟,可以使用 Fetch Priority 来早地加载图像。
// 几种使用方式
<img src="/images/in_viewport_but_not_important.svg" fetchpriority="low" alt="I'm an unimportant image!">
<link rel="preload" href="/js/script.js" as="script" fetchpriority="low">
<script>
fetch('https://example.com/', {priority: 'low'})
.then(data => {});
</script>
资源优先级
资源下载顺序取决于浏览器为页面的每个资源分配的优先级。不同的因素会影响优先级计算逻辑。
- CSS、字体、脚本、图片和第三方资源分配不同的优先级。
- 在文档中引用资源的位置或顺序也会影响资源的优先级。
- preload 资源提示有助于浏览器更快地发现资源,从而在文档加载之前加载资源,并影响优先级。
- script 设置了 async 和 defer 也会影响优先级
当前大多数资源在Chrome中的优先级和顺序
布局阻塞 | 在布局阻塞阶段加载 | 在布局阻塞阶段逐个加载资源 | |
---|---|---|---|
Blink 优先级 | VeryHigh | High | Medium Low VeryLow |
DevTools 优先级 | Highest | High | Medium Low Lowest |
主要资源 | |||
CSS*** (early**) | CSS*** (late**) ## CSS (mismatch) | ||
Script (early** or not from preload scanner) | Script (**late) Script (async) ## | ||
Font | Font (preload) | ||
Import | |||
视口中的 Image | ## Image ## | ||
## Media ## | |||
## SVG document ## | |||
## ## Prefetch | |||
Preload* | |||
XHR (sync) | XHR/fetch* (async) |
-
'*' 使用
as
进行预加载或使用了"type"的 fetch 会使用它们请求的类型的优先级(例如,预加载 as="stylesheet" 将使用 Highest 优先级)。如果没有 "as",它们会表现得像 XHR。-
fetch('image.jpg', { type: 'image/jpeg' })
,浏览器会根据请求的资源类型来确定它的优先级。 -
<link rel="preload" href="styles.css" as="style">
-
-
'**' "Early": 在请求任何非预加载图像之前的请求("late" 是之后)
-
'***' 如果 CSS 的媒体查询类型不匹配,就不会被预加载扫描器获取,并且只会在主解析器到达时处理,这通常意味着它会被很晚地获取并且具有"late"优先级。
解释下第3点:
<link rel="stylesheet" href="styles.css" media="print">
在这个link中,styles.css 的媒体类型为 print
,而浏览器在预加载时可能会忽略它,因为当前页面加载的是 "screen" 媒体类型的样式。只有当页面主解析器达到 "styles.css" 样式表时,它才会被处理,这可能发生得很晚,因此它的优先级可能是"late"。
看下前后的优先级:
什么时候需要用 fetchPriority 🍒
首先,了解浏览器的优先级逻辑可以帮助你调整下载顺序。通过以下方式来控制浏览器的优先级计算,从而改善性能和核心 Web Vitals:
- 根据希望下载它们的顺序,放置资源标签,如
- 用 preload 资源提示来尽早下载必要的资源,特别是那些浏览器不容易早期发现的资源。
- 用 async 或 defer 异步下载脚本,而不会阻塞其他资源。
- 懒加载屏幕以外的内容,以便浏览器可以为更重要的内容更快的下载
在某些情况下,这些方法可能不太够用,这时候可以尝试下 fetchPriority :
-
比如轮播图,一般刚开始就会出现在视口中,但不必都具有相同的优先级,只有第一个可见的图像需要比其他图像具有更高的优先级(YouTube 视频预览图同理)。
-
有的视口内的主要图像是 "Low" 优先级,这一般会能感受到明显延迟。在标记中提供Fetch优先级可以让图像以“高”优先级开始,并更早地开始加载。
注意:CSS 中 background 中的 LCP 图像,仍然需要使用预加载(
preload
)。可以通过在预加载元素上添加fetchpriority='high'
来与 Fetch Priority 结合使用,否则图像仍将以默认的“低”优先级开始加载。 -
将脚本声明为异步(async)或延迟(defer)。这样脚本就是“low”优先级。我们可以添加
fetchpriority
提高它们的优先级,同时确保异步下载。 -
还可以使用
fetch
来异步获取资源或数据。fetch 是“High”优先级。但有时候,我们可能不希望所有的 fetch 都以“High”优先级执行,比如初始化页面时,同时请求几个接口,想要某一部分数据最快展示出来。 -
浏览器将CSS和字体看成“High”优先级,但是对于LCP来说,并非所有这些资源都同等重要或必需。可以使用Fetch Priority来降低其中一些资源的优先级。
兼容性
惨不忍睹,但是不影响使用
如果学到了新知识,麻烦点个 👍 和 ⭐
转载自:https://juejin.cn/post/7268070933893005370