首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >浏览器之资源获取优先级(fetchpriority)

浏览器之资源获取优先级(fetchpriority)

作者头像
前端柒八九
发布2023-08-10 15:39:27
发布2023-08-10 15:39:27
1.6K0
举报

前言

最近,公司在做技术改造升级,老旧项目优化。因为是B端项目居多,所以优化方向也是基于浏览器端的项目改造和处理。

然后,在进行实操时发现,资源的加载是很影响页面性能的。而针对资源加载而言,根据资源的重要性,又可以做一些符合业务逻辑的处理。今天,我们就来讲讲关于「影响页面资源加载的属性」 - fetchpriority

Last but not least,这偏文章算是一个引子,之后我们会出一篇关于如何对一个现有网站的性能分析。同时,因为我们有文章分类,并且该文章内容大部分都是关于浏览器的。所以,我们就将其归类为「浏览器相关」的文章体系。

你能所学到的知识点

  1. 前置知识点
  2. Fetch Priority
  3. fetchpriority
  4. 案例分析
  5. 将 preload 和 fetchpriority 合并
  6. fetchpriority 的好处

前置知识点

页面阶段

通常一个页面有「三个阶段」

  1. 「加载阶段」
    • 是指从「发出请求到渲染出完整页面」的过程
    • 影响到这个阶段的主要因素有「网络」「JavaScript 脚本」
  2. 「交互阶段」
    • 主要是从页面加载完成到「用户交互」的整个过程
    • 影响到这个阶段的主要因素是 「JavaScript 脚本」
  3. 「关闭阶段」
    • 主要是用户发出关闭指令后页面所做的一些「清理操作」

加载阶段-资源获取

我们可以通过PerformanceNavigationTiming[1]来简单的看一下,浏览器在资源加载时候,所经历的大体流程。

在上图中,Resource Timing就是在为了做资源获取的所做的准备工作。(这里涉及到网络处理相关的,我们之前也有文章介绍,如果感兴趣,可以移步到指定文章,按个人情况,自行获取)

我们将上图,做一个精简处理。

然后,我们简单的把上述的各个阶段,做一个简单的介绍。

时间戳

描述

startTime

资源加载过程开始之前的时间戳

redirectStart

触发重定向时的时间戳

redirectEnd

接收到最后一个重定向响应的最后一个字节之后的时间戳

workerStart

Service Worker线程开始之前的时间戳

fetchStart

浏览器开始获取资源之前的时间戳

domainLookupStart

浏览器开始进行资源的域名查询之前的时间戳

domainLookupEnd

浏览器完成资源的域名查询之后的时间戳

connectStart

浏览器开始建立与服务器的连接以检索资源之前的时间戳

secureConnectionStart

如果资源通过安全连接加载,则是在浏览器开始握手过程以保证当前连接安全之前的时间戳

connectEnd

浏览器完成与服务器建立连接之后的时间戳

requestStart

浏览器开始从服务器、缓存或本地资源请求资源之前的时间戳

responseStart

浏览器从服务器、缓存或本地资源接收到响应的第一个字节之后的时间戳

responseEnd

浏览器接收到资源的最后一个字节之后的时间戳,或者在传输连接关闭之前的时间戳(以先到者为准)

这些时间戳描述了资源加载过程中的不同阶段,通过它们可以了解各个阶段的时间信息,从而进行性能优化和分析。


加载阶段-页面渲染

这里可以直接参考我们之前的文章像素是怎样练成的。 这里就不在赘述了。(看过的人,都说好;如果不好,记得回来打我🐶)


Chromium 加载资源的阶段

Chromium 浏览器在加载资源时采用了两个阶段。

  1. 紧凑模式Tight mode
  2. 空闲模式Idle mode

紧凑模式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是指在「网页加载过程」中会「阻止浏览器进行渲染」的资源。 ❞

这些资源需要在浏览器能够「继续渲染页面之前」先加载和处理。渲染阻断资源的加载时间较长,会延迟网页的首次渲染用户能够与页面进行交互的时间。

以下是常见的渲染阻断资源

  1. CSS「外部样式表(CSS)文件」是常见的渲染阻断资源
    • 浏览器在解析 HTML 时会发现外部 CSS 文件,并且需要等待 CSS 文件下载解析完成后才能继续渲染页面。
    • 如果 CSS 文件体积较大或加载时间较长,将会显著延迟页面的渲染。
  2. JavaScriptJavaScript 脚本也可以成为渲染阻断资源
    • 当浏览器遇到 <script> 标签时,会阻塞渲染,等待 JavaScript 文件的下载执行完成后才能继续渲染页面。
    • 如果 JavaScript 文件较大或执行时间较长,会对页面的渲染速度产生较大影响。
  3. 字体:自定义字体文件(如WOFFWOFF2TTF等)也可能成为渲染阻断资源
    • 当网页使用自定义字体时,浏览器需要下载解析字体文件后才能正确渲染文本内容
    • 如果字体文件较大,会延迟页面的渲染。

换句话说,渲染阻塞资源是一个组件,它将「不允许浏览器渲染整个DOM树,直到给定的资源被完全加载和解析/执行」。在渲染阻塞资源完全加载之前,你无法渲染树。


解析器阻断资源

❝解析器阻断资源Parser-Blocking Resources是指在「浏览器解析 HTML 文档时」会阻塞解析器的资源。 ❞

这些资源需要在浏览器能够「继续解析文档之前」先加载和处理。解析器阻断资源的加载时间较长,会延迟「整个文档的解析和渲染」

以下是常见的解析器阻断资源

  1. 外部脚本「外部 JavaScript 脚本」是常见的解析器阻断资源
    • 当浏览器遇到 <script> 标签引用「外部 JavaScript 文件」时,解析器会暂停解析 HTML 文档,等待 JavaScript 文件的下载执行完成后才能继续解析文档。
  2. 外部样式表「外部 CSS 样式表」也可以成为解析器阻断资源。
    • 当浏览器遇到 <link rel="stylesheet"> 标签引用外部 CSS 文件时,解析器会停止解析文档,等待 CSS 文件的下载解析完成后才能继续解析。
  3. 图像资源:在某些情况下,大型图像资源也可能成为解析器阻断资源。
    • 当浏览器遇到 <img> 标签或 CSS 中的 background-image 属性引用图像时,解析器会暂停解析文档,等待图像资源的下载完成后才能继续解析。

换句话说,当需要「下载」「执行」解析器阻断资源时,浏览器会「暂停执行和构建DOM树」。当解析器阻断资源被执行完后,DOM树的构建才继续进行。


渲染阻断资源 VS 解析器阻断资源

渲染阻断资源解析器阻断资源是两种不同类型的资源,它们在浏览器加载和处理过程中起着不同的作用。

  1. 渲染阻断资源:渲染阻断资源是指在「网页加载过程中会阻止浏览器进行渲染的资源」
    • 这些资源需要在浏览器能够「继续渲染页面之前」先加载和处理。
    • 常见的渲染阻断资源包括外部样式表(CSS)JavaScript 脚本
    • 渲染阻断资源会延迟网页的首次渲染(First Paint)和用户能够与页面进行交互的时间(TTI)。
  2. 解析器阻断资源:解析器阻断资源是指在「浏览器解析 HTML 文档时会阻塞解析器的资源」
    • 这些资源需要在浏览器能够「继续解析文档之前」先加载和处理。
    • 常见的解析器阻断资源包括外部 JavaScript 脚本外部样式表
    • 解析器阻断资源会「延迟整个文档的解析过程和后续资源的请求」

区别: 下面是渲染阻断资源和解析器阻断资源的区别

特性

渲染阻断资源

解析器阻断资源

作用对象

页面的「渲染过程」

页面的「解析过程」

阻塞时机

在浏览器进行页面渲染之前阻塞

在浏览器进行 HTML 解析之前阻塞

影响范围

页面的渲染速度和用户交互能力

整个文档的解析速度和后续资源的加载

常见类型

外部样式表和 JavaScript 脚本

「外部 JavaScript 脚本」和外部样式表

❝某些资源可能「同时具有渲染阻断解析器阻断的特性」,具体影响取决于资源的类型和加载顺序。 ❞

❝当然,在我们平时开发和项目优化中,我们不需要对资源做是否是渲染阻断资源解析器阻断资源的区分。 我们也可以一股脑的认为上述所提出的资源都是「阻塞资源」。最终的结果就是影响页面的首次渲染和页面交互时间。 ❞


查看chromium

如果大家对chrome或者chromium中源码结构或者一些内部实现感兴趣。可以通过Chromium Code Search[2]进行查看。

因为,里面的Chromium的内部实现,有很多并且专业术语也冗余庞杂,如果想了解这块的东西,我们以后可以单出一篇文章,给大家简单介绍一下,如何查看Chromium源码。


WebPageTest

在进行网页性能分析其实有很多工具和插件。例如,Chrome自带的Ligthhouse/Performance/Recorder/Performance insights等。(针对这块也是有很大的学问和实践规范。后期,我们也会有相关的文章和系列)。

而今天的文章的一些图文信息,我们使用WebPageTest

WebPageTest 是一个免费的在线性能测试工具[3],用于评估网页加载速度和性能。它可以帮助开发人员和网站管理员分析网页的性能,并提供改进性能的建议。

以下是 WebPageTest 的一些主要特点和功能:

  1. 多地点测试:WebPageTest 提供了全球各地的测试服务器,可以选择多个地点进行性能测试,以模拟不同地区用户的加载体验。
  2. 多种浏览器和设备:WebPageTest 支持使用多种浏览器和设备进行测试,包括桌面浏览器(如ChromeFirefoxSafari)和移动设备浏览器(如iOS和Android)。
  3. 多种测试选项:WebPageTest 提供了丰富的测试选项,可以对页面加载过程进行详细的性能分析,包括测量页面加载时间、网络请求和响应时间、渲染时间等。
  4. 完整的性能报告:测试完成后,WebPageTest 会生成详细的性能报告,包括加载时间的时间线图、资源加载顺序、性能指标(如首次字节时间、首次可交互时间等)、页面截图等。
  5. 延迟和带宽模拟:WebPageTest 允许模拟不同的网络条件,包括延迟和带宽限制,以测试在不同网络环境下的页面加载速度和性能。
  6. 性能优化建议:WebPageTest 提供了针对页面性能的建议和优化提示,帮助开发人员识别和解决性能瓶颈,改进页面加载速度和用户体验。

WebPageTest 是一个功能强大的性能测试工具,广泛应用于网站开发和优化过程中。通过使用 WebPageTest,开发人员可以更好地了解页面加载过程中的性能瓶颈,并采取相应的优化措施,提升网站的用户体验和性能。


Fetch Priority

Fetch Priority API 用于向浏览器指示资源的「相对优先级」。可以通过向 <img><link><script><iframe> 元素添加 fetchpriority 属性或通过 Fetch API 上的 priority 属性来配置优先级。

❝浏览器主要根据「请求的类型」和在「文档标记中的位置」来确定请求的优先级。 ❞

下面是一些示例和相应的代码,以说明不同资源的优先级:

  1. CSS 文件:在文档的 <head> 中请求的 CSS 文件通常被赋予「最高优先级」
代码语言:javascript
复制
<head>
  <link rel="stylesheet" href="styles.css">
</head>
  1. JavaScript 文件:一般情况下,没有 asyncdefer 属性的 <script> 元素将被视为阻塞渲染资源,并被赋予「较高优先级」
代码语言:javascript
复制
<script src="script.js"></script>
  1. 图像:图像通常具有「较低的默认优先级」。我们可以通过添加 fetchpriority 属性来调整图像的优先级。
代码语言:javascript
复制
<img src="image.jpg" fetchpriority="high">
  1. 预加载资源:使用 <link rel="preload"> 元素可以预先加载资源,但它不会直接影响资源的优先级。
代码语言:javascript
复制
<link rel="preload" href="resource.js" as="script">

除了一些特殊的资源,对于其他常规的资源,浏览器按照「发现资源的顺序」下载具有相同优先级的资源。


fetchpriority

fetchpriority 属性可以用于提示浏览器增加降低所请求资源的优先级。 ❞

该枚举属性可以有三个值:

  • high : 该资源「相对于其默认优先级」更高
  • low : 该资源相「对于其默认优先级」更低
  • auto : 默认值

Chromium源码中,我们找到对应的定义。

举例说明

代码语言:javascript
复制
<img src="/789.jpg" alt="前端柒八九" fetchpriority="high" />

在上面的示例中,我们提示浏览器 <img> 的优先级比其默认优先级高。

对于 fetch 方法上的 priority 属性,同样支持相同的值。

代码语言:javascript
复制
fetch("/api/data.json", { priority: 'high' })

在上面的 fetch 请求中,我们向浏览器指示该 fetch 请求的优先级较其默认优先级更高。


Default priority

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的媒体类型不匹配时,「预加载扫描器」不会获取该CSS,而只有当主解析器到达时才会处理它,这通常意味着它将在非常晚的时候被获取,并且具有"late"优先级。

优先级变化

图像始终以低优先级开始。如果在布局过程中发现「图像在视口内」,则优先级将提升为高优先级,尽管这可能发生在加载过程中的相当晚的阶段。

位于「页面底部并阻塞的脚本」中等优先级。但是,如果主HTML解析器到达并被阻塞,优先级将提升为高优先级。(前面我们讲过,js解析器阻断资源)

网络堆栈优先级名称

顺便说一嘴,在ChromeNetworkDevTool中也会显示资源优先级。

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> 中的阻塞脚本被下载并执行完成(带有 asyncdefer 的脚本不会阻塞渲染),初始阶段就完成了。「即使有超过两个同时进行的请求,浏览器现在可以根据资源的优先级和在标记中的顺序继续下载任何剩余的资源」

在上面的图表中,一旦渲染阻塞的 JavaScript「下载并执行」(粉色条),浏览器开始下载图片,即使两个 CSS 文件仍在进行中。黄色的垂直条表示 DOM 可交互(即 readystatechange 事件被触发)的时间点。


案例分析

preconnet

如果图片位于不同的域名上,浏览器在下载文件之前需要打开到该域名的连接。

这在 WebPageTest 的图表中显示为绿色橙色洋红色的条形图,表示在下载之前的预连接过程。

我们可以使用 preconnect 资源提示来提前开始下载图片。

在上面的图表中,在初始阶段之前,浏览器打开了与 cdn.glitch.global 域的连接,这使得浏览器能够开始下载文件。一旦浏览器退出初始阶段(黄色垂直线),它立即开始下载图片,从而节省了约 350 毫秒的时间。


preload

preload 指令允许你向浏览器提供关于“晚发现”(late-discovered)的关键资源的信息。这对于在样式表或脚本中加载的资源特别有用,例如背景图片字体。 ❞

在我们的示例中,图片在标记中声明并且早早被发现,因此 preload 的效果很小。(效果有,但是不多)

在上面的图表中,我们用以下内容替代了 preconnect

代码语言:javascript
复制
<link
  rel="preload"
  as="image"
  href="https://cdn.glitch.global/.../image-1.jpg"
/>

尽管使用了 preload,但图片仍然要等到同时进行的请求少于两个时才开始下载。

预加载资源类型

这里在额外说一些,关于哪些资源可以使用prelaod


fetchpriority

既然perlaod在有些场景中效果不是很好,那么我们可以另谋出路。

我们可以使用 Fetch Priority 来向浏览器指示 image-1.jpg 的优先级比默认优先级更高,使用以下方式:

代码语言:javascript
复制
<img
  src="https://cdn.glitch.global/.../image-1.jpg"
  fetchpriority="high"
  alt=""
/>

这将把图片的「初始优先级从低优先级提升到高优先级,使得图片可以在初始阶段被加载」

上面的瀑布图显示了在「初始阶段与其他关键资源并行加载」image-1.jpg。这给我们带来了迄今为止最大的改进。


将 preload 和 fetchpriority 合并

到目前为止,Fetch Priority 只在基于 Chromium 的浏览器上受支持,然而,它在不支持识别 fetchpriority 属性的浏览器上会有优雅的失败处理。这使得我们可以将 preload 指令与 Fetch Priority 结合使用。

代码语言:javascript
复制
<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 提示浏览器提前下载图像。

后记

「分享是一种态度」

参考资料:

  1. PerformanceNavigationTiming[5]
  2. Resource timing[6]
  3. Chrome Resource Priorities and Scheduling[7]
  4. WebPageTest[8]

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/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端柒八九 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 页面阶段
    • 加载阶段-资源获取
    • 加载阶段-页面渲染
  • Chromium 加载资源的阶段
  • 资源类型
    • 关键渲染路径
    • 渲染阻断资源
    • 解析器阻断资源
    • 渲染阻断资源 VS 解析器阻断资源
  • 查看chromium
  • WebPageTest
  • Fetch Priority
  • fetchpriority
    • 举例说明
    • Default priority
      • 优先级变化
      • 网络堆栈优先级名称
    • 紧凑模式(Tight mode)
  • 案例分析
    • preconnet
    • preload
      • 预加载资源类型
    • fetchpriority
  • 将 preload 和 fetchpriority 合并
  • fetchpriority 的好处
  • 总结
  • 后记
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档