
前言
最近,公司在做技术改造升级,老旧项目优化。因为是B端项目居多,所以优化方向也是基于浏览器端的项目改造和处理。
然后,在进行实操时发现,资源的加载是很影响页面性能的。而针对资源加载而言,根据资源的重要性,又可以做一些符合业务逻辑的处理。今天,我们就来讲讲关于「影响页面资源加载的属性」 - fetchpriority。
Last but not least,这偏文章算是一个引子,之后我们会出一篇关于如何对一个现有网站的性能分析。同时,因为我们有文章分类,并且该文章内容大部分都是关于浏览器的。所以,我们就将其归类为「浏览器相关」的文章体系。
你能所学到的知识点
❝
❞
前置知识点
通常一个页面有「三个阶段」
我们可以通过PerformanceNavigationTiming[1]来简单的看一下,浏览器在资源加载时候,所经历的大体流程。
在上图中,Resource Timing就是在为了做资源获取的所做的准备工作。(这里涉及到网络处理相关的,我们之前也有文章介绍,如果感兴趣,可以移步到指定文章,按个人情况,自行获取)
我们将上图,做一个精简处理。
然后,我们简单的把上述的各个阶段,做一个简单的介绍。
时间戳 | 描述 |
|---|---|
startTime | 资源加载过程开始之前的时间戳 |
redirectStart | 触发重定向时的时间戳 |
redirectEnd | 接收到最后一个重定向响应的最后一个字节之后的时间戳 |
workerStart | Service Worker线程开始之前的时间戳 |
fetchStart | 浏览器开始获取资源之前的时间戳 |
domainLookupStart | 浏览器开始进行资源的域名查询之前的时间戳 |
domainLookupEnd | 浏览器完成资源的域名查询之后的时间戳 |
connectStart | 浏览器开始建立与服务器的连接以检索资源之前的时间戳 |
secureConnectionStart | 如果资源通过安全连接加载,则是在浏览器开始握手过程以保证当前连接安全之前的时间戳 |
connectEnd | 浏览器完成与服务器建立连接之后的时间戳 |
requestStart | 浏览器开始从服务器、缓存或本地资源请求资源之前的时间戳 |
responseStart | 浏览器从服务器、缓存或本地资源接收到响应的第一个字节之后的时间戳 |
responseEnd | 浏览器接收到资源的最后一个字节之后的时间戳,或者在传输连接关闭之前的时间戳(以先到者为准) |
这些时间戳描述了资源加载过程中的不同阶段,通过它们可以了解各个阶段的时间信息,从而进行性能优化和分析。
这里可以直接参考我们之前的文章像素是怎样练成的。 这里就不在赘述了。(看过的人,都说好;如果不好,记得回来打我🐶)
Chromium 浏览器在加载资源时采用了两个阶段。
❝
❞
紧凑模式Tight mode是初始阶段,它会「限制加载低优先级的资源」,直到文档的<body>被追加到文档中(基本上,在<head>中的所有阻塞脚本执行完毕后)。在紧凑模式下,只有在发现这些低优先级资源时,「同时存在不超过2个正在进行的请求」,才会加载它们。
除了 紧凑模式Tight mode之外,Chromium 浏览器还有一个阶段称为 空闲模式Idle mode。
在 空闲模式Idle mode 中,浏览器会「在页面空闲时加载资源」。它会根据资源的优先级和是否可见来决定何时加载资源,以提高性能和用户体验。
❝关键资源Critical Resource是指对「网页性能」和「加载速度」影响最大的资源。它们是在网页的关键渲染路径Critical Rendering Path上,对
首次渲染和用户交互有着直接影响的资源。 ❞
或者说:关键资源就是所有可能「阻碍页面渲染」的资源
❝浏览器的关键渲染路径Critical Rendering Path是指浏览器在
加载和渲染网页时所经过的一系列关键步骤,以便将网页内容呈现给用户。 ❞
下面是关键渲染路径的主要步骤以及对应的说明:
步骤 | 说明 |
|---|---|
解析 HTML | 解析服务器返回的 HTML 文档,构建 DOM 树。 |
解析 CSS | 解析 CSS 样式表,构建 CSSOM 树。 |
合成渲染树 | 结合 DOM 树和 CSSOM 树生成渲染树,包括可见元素和样式布局信息。 |
布局计算 | 对渲染树进行布局计算,确定元素在屏幕上的位置和大小。 |
绘制 | 根据渲染树和布局计算的结果,将页面内容绘制到屏幕上。 |
栅格化 | 将绘制的内容拆分成小的图块,方便传输和显示。 |
合成 | 将栅格化后的图块组合成一帧画面,显示在屏幕上。 |
这些步骤构成了浏览器渲染页面的关键路径。关于详细的浏览器如何渲染页面的步骤,可以参考像素是怎样练成的。
❝渲染阻断资源Render-Blocking Resources是指在「网页加载过程」中会「阻止浏览器进行渲染」的资源。 ❞
这些资源需要在浏览器能够「继续渲染页面之前」先加载和处理。渲染阻断资源的加载时间较长,会延迟网页的首次渲染和用户能够与页面进行交互的时间。
以下是常见的渲染阻断资源:
CSS:「外部样式表(CSS)文件」是常见的渲染阻断资源。下载和解析完成后才能继续渲染页面。JavaScript:JavaScript 脚本也可以成为渲染阻断资源。<script> 标签时,会阻塞渲染,等待 JavaScript 文件的下载和执行完成后才能继续渲染页面。JavaScript 文件较大或执行时间较长,会对页面的渲染速度产生较大影响。WOFF、WOFF2、TTF等)也可能成为渲染阻断资源下载和解析字体文件后才能正确渲染文本内容换句话说,渲染阻塞资源是一个组件,它将「不允许浏览器渲染整个DOM树,直到给定的资源被完全加载和解析/执行」。在渲染阻塞资源完全加载之前,你无法渲染树。
❝解析器阻断资源Parser-Blocking Resources是指在「浏览器解析 HTML 文档时」会阻塞解析器的资源。 ❞
这些资源需要在浏览器能够「继续解析文档之前」先加载和处理。解析器阻断资源的加载时间较长,会延迟「整个文档的解析和渲染」。
以下是常见的解析器阻断资源:
外部脚本:「外部 JavaScript 脚本」是常见的解析器阻断资源。<script> 标签引用「外部 JavaScript 文件」时,解析器会暂停解析 HTML 文档,等待 JavaScript 文件的下载和执行完成后才能继续解析文档。外部样式表:「外部 CSS 样式表」也可以成为解析器阻断资源。<link rel="stylesheet"> 标签引用外部 CSS 文件时,解析器会停止解析文档,等待 CSS 文件的下载和解析完成后才能继续解析。图像资源:在某些情况下,大型图像资源也可能成为解析器阻断资源。<img> 标签或 CSS 中的 background-image 属性引用图像时,解析器会暂停解析文档,等待图像资源的下载完成后才能继续解析。换句话说,当需要「下载」和「执行」解析器阻断资源时,浏览器会「暂停执行和构建DOM树」。当解析器阻断资源被执行完后,DOM树的构建才继续进行。
渲染阻断资源和解析器阻断资源是两种不同类型的资源,它们在浏览器加载和处理过程中起着不同的作用。
渲染阻断资源:渲染阻断资源是指在「网页加载过程中会阻止浏览器进行渲染的资源」。外部样式表(CSS)和 JavaScript 脚本。首次渲染(First Paint)和用户能够与页面进行交互的时间(TTI)。解析器阻断资源:解析器阻断资源是指在「浏览器解析 HTML 文档时会阻塞解析器的资源」。外部 JavaScript 脚本和外部样式表。区别: 下面是渲染阻断资源和解析器阻断资源的区别
特性 | 渲染阻断资源 | 解析器阻断资源 |
|---|---|---|
作用对象 | 页面的「渲染过程」 | 页面的「解析过程」 |
阻塞时机 | 在浏览器进行页面渲染之前阻塞 | 在浏览器进行 HTML 解析之前阻塞 |
影响范围 | 页面的渲染速度和用户交互能力 | 整个文档的解析速度和后续资源的加载 |
常见类型 | 外部样式表和 JavaScript 脚本 | 「外部 JavaScript 脚本」和外部样式表 |
❝某些资源可能「同时具有
渲染阻断和解析器阻断的特性」,具体影响取决于资源的类型和加载顺序。 ❞❝当然,在我们平时开发和项目优化中,我们不需要对资源做是否是
渲染阻断资源和解析器阻断资源的区分。 我们也可以一股脑的认为上述所提出的资源都是「阻塞资源」。最终的结果就是影响页面的首次渲染和页面交互时间。 ❞
如果大家对chrome或者chromium中源码结构或者一些内部实现感兴趣。可以通过Chromium Code Search[2]进行查看。
因为,里面的Chromium的内部实现,有很多并且专业术语也冗余庞杂,如果想了解这块的东西,我们以后可以单出一篇文章,给大家简单介绍一下,如何查看Chromium源码。
在进行网页性能分析其实有很多工具和插件。例如,Chrome自带的Ligthhouse/Performance/Recorder/Performance insights等。(针对这块也是有很大的学问和实践规范。后期,我们也会有相关的文章和系列)。
而今天的文章的一些图文信息,我们使用WebPageTest。
WebPageTest 是一个免费的在线性能测试工具[3],用于评估网页加载速度和性能。它可以帮助开发人员和网站管理员分析网页的性能,并提供改进性能的建议。
以下是 WebPageTest 的一些主要特点和功能:
WebPageTest 提供了全球各地的测试服务器,可以选择多个地点进行性能测试,以模拟不同地区用户的加载体验。WebPageTest 支持使用多种浏览器和设备进行测试,包括桌面浏览器(如Chrome、Firefox、Safari)和移动设备浏览器(如iOS和Android)。WebPageTest 提供了丰富的测试选项,可以对页面加载过程进行详细的性能分析,包括测量页面加载时间、网络请求和响应时间、渲染时间等。WebPageTest 会生成详细的性能报告,包括加载时间的时间线图、资源加载顺序、性能指标(如首次字节时间、首次可交互时间等)、页面截图等。WebPageTest 允许模拟不同的网络条件,包括延迟和带宽限制,以测试在不同网络环境下的页面加载速度和性能。WebPageTest 提供了针对页面性能的建议和优化提示,帮助开发人员识别和解决性能瓶颈,改进页面加载速度和用户体验。WebPageTest 是一个功能强大的性能测试工具,广泛应用于网站开发和优化过程中。通过使用 WebPageTest,开发人员可以更好地了解页面加载过程中的性能瓶颈,并采取相应的优化措施,提升网站的用户体验和性能。
Fetch Priority API 用于向浏览器指示资源的「相对优先级」。可以通过向 <img>、<link>、<script> 和 <iframe> 元素添加 fetchpriority 属性或通过 Fetch API 上的 priority 属性来配置优先级。
❝浏览器主要根据「请求的类型」和在「文档标记中的位置」来确定请求的优先级。 ❞
下面是一些示例和相应的代码,以说明不同资源的优先级:
<head> 中请求的 CSS 文件通常被赋予「最高优先级」。<head>
<link rel="stylesheet" href="styles.css">
</head>
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属性可以用于提示浏览器增加或降低所请求资源的优先级。 ❞
该枚举属性可以有三个值:
high : 该资源「相对于其默认优先级」更高low : 该资源相「对于其默认优先级」更低auto : 默认值从Chromium源码中,我们找到对应的定义。

<img src="/789.jpg" alt="前端柒八九" fetchpriority="high" />
在上面的示例中,我们提示浏览器 <img> 的优先级比其默认优先级高。
对于 fetch 方法上的 priority 属性,同样支持相同的值。
fetch("/api/data.json", { priority: 'high' })
在上面的 fetch 请求中,我们向浏览器指示该 fetch 请求的优先级较其默认优先级更高。
Fetch Priority API 可以增加或降低资源相对于其默认优先级的优先级。
例如,默认情况下,图片始终具有低优先级。将 fetchpriority="high" 分配给图片将把它们的优先级提升为高优先级。
另一方面,渲染阻塞的样式表默认情况下具有「最高优先级」。将其分配为 fetchpriority="low" 将把其「优先级降低为高优先级,而不是低优先级」。
❝
fetchpriority用于「相对于默认值」调整资源的优先级,而不是显式设置其值。 ❞
在 `Chromium` 的资源优先级文档[4]中记录了 Fetch Priority 对资源优先级的影响,包括不同的资源类型,它们的默认优先级(◉),以及使用 fetchpriority="high"(⬆)和 fetchpriority="low"(⬇)时的结果优先级。


"as"进行preload或使用"type"进行fetch的操作将使用它们请求的类型的优先级,除非另有说明(比如字体)。"preload as=stylesheet"将使用最高优先级。如果没有指定"as",它们将表现得像XHR(XMLHttpRequest)。"Early"指的是在请求任何「非预加载的图像之前」进行的请求("late"指的是之后)。媒体类型不匹配时,「预加载扫描器」不会获取该CSS,而只有当主解析器到达时才会处理它,这通常意味着它将在非常晚的时候被获取,并且具有"late"优先级。图像始终以低优先级开始。如果在布局过程中发现「图像在视口内」,则优先级将提升为高优先级,尽管这可能发生在加载过程中的相当晚的阶段。
位于「页面底部并阻塞的脚本」为中等优先级。但是,如果主HTML解析器到达并被阻塞,优先级将提升为高优先级。(前面我们讲过,js是解析器阻断资源)
顺便说一嘴,在Chrome中Network的DevTool中也会显示资源优先级。
Chrome网络堆栈中显示的资源优先级名称与Chromium中的Blink中有些不同。但是,它们在自己的规则范围中,是能正确表达各个资源之间的优先级关系的。
完整的映射如下:
Chrome网络堆栈优先级名称 | Chrome优先级名称 |
|---|---|
IDLE | Lowest |
LOWEST | Low |
LOW | Medium |
MEDIUM | High |
HIGHEST | Highest |
在前面的「前置知识」中我们已经讲过何为紧凑模式Tight mode,并且还将其与空闲模式Idle mode进行了对比。这里就不在赘述了。

在上面的瀑布图中,您可以看到资源 image-1.jpg 直到 style-2.css 完成下载后才开始下载,即使它已经被解析器探知。此时,「只剩下一个」正在处理的资源 - script.js,所以浏览器开始下载低优先级的图片。
一旦所有位于 <head> 中的阻塞脚本被下载并执行完成(带有 async 或 defer 的脚本不会阻塞渲染),初始阶段就完成了。「即使有超过两个同时进行的请求,浏览器现在可以根据资源的优先级和在标记中的顺序继续下载任何剩余的资源」。

在上面的图表中,一旦渲染阻塞的 JavaScript 被「下载并执行」(粉色条),浏览器开始下载图片,即使两个 CSS 文件仍在进行中。黄色的垂直条表示 DOM 可交互(即 readystatechange 事件被触发)的时间点。
如果图片位于不同的域名上,浏览器在下载文件之前需要打开到该域名的连接。

这在 WebPageTest 的图表中显示为绿色、橙色和洋红色的条形图,表示在下载之前的预连接过程。
我们可以使用 preconnect 资源提示来提前开始下载图片。

在上面的图表中,在初始阶段之前,浏览器打开了与 cdn.glitch.global 域的连接,这使得浏览器能够开始下载文件。一旦浏览器退出初始阶段(黄色垂直线),它立即开始下载图片,从而节省了约 350 毫秒的时间。
❝
preload指令允许你向浏览器提供关于“晚发现”(late-discovered)的关键资源的信息。这对于在样式表或脚本中加载的资源特别有用,例如背景图片或字体。 ❞
在我们的示例中,图片在标记中声明并且早早被发现,因此 preload 的效果很小。(效果有,但是不多)

在上面的图表中,我们用以下内容替代了 preconnect :
<link
rel="preload"
as="image"
href="https://cdn.glitch.global/.../image-1.jpg"
/>
尽管使用了 preload,但图片仍然要等到同时进行的请求少于两个时才开始下载。
这里在额外说一些,关于哪些资源可以使用prelaod。

既然perlaod在有些场景中效果不是很好,那么我们可以另谋出路。
我们可以使用 Fetch Priority 来向浏览器指示 image-1.jpg 的优先级比默认优先级更高,使用以下方式:
<img
src="https://cdn.glitch.global/.../image-1.jpg"
fetchpriority="high"
alt=""
/>
这将把图片的「初始优先级从低优先级提升到高优先级,使得图片可以在初始阶段被加载」。

上面的瀑布图显示了在「初始阶段与其他关键资源并行加载」的 image-1.jpg。这给我们带来了迄今为止最大的改进。
到目前为止,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的好处是指资源被发现的时间与开始下载的时间之间的差异。我将其称为机会。因此,如果资源早早被发现,但浏览器开始下载它的时间较晚,那么机会就更大。 ❞
如果图像来自不同的域名,还可以将将建立连接的时间包括在机会中。
由于篇幅有限,关于LCP的内容,这里先不展开,我们会单独出一篇文章。
preconnect 提前打开连接。preload 告知浏览器在请求前下载图像。fetchpriority 提示浏览器提前下载图像。「分享是一种态度」。
参考资料:
Reference
[1]
PerformanceNavigationTiming: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming
[2]
Chromium Code Search: https://source.chromium.org/chromium/chromium/src;l=826
[3]
免费的在线性能测试工具: https://www.webpagetest.org/
[4]
在 Chromium 的资源优先级文档: https://docs.google.com/document/d/1bCDuq9H1ih9iNjgzyAL0gpwNFiEP4TZS-YLRp_RuMlc/edit
[5]
PerformanceNavigationTiming: https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigationTiming
[6]
Resource timing: https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/Resource_timing
[7]
Chrome Resource Priorities and Scheduling: https://docs.google.com/document/d/1bCDuq9H1ih9iNjgzyAL0gpwNFiEP4TZS-YLRp_RuMlc/edit
[8]
WebPageTest: https://docs.webpagetest.org/