修复 Lighthouse 中的"避免链接关键请求"问题。

Arjen Karel Core Web Vitals Consultant
Arjen Karel
linkedin

"避免链接关键请求"简述

关键请求是浏览器以高优先级获取的网络请求。

当页面或脚本导致多个资源以高优先级下载时,我们称之为关键请求链。

浏览器在所有关键资源下载完成之前不会(完全)开始渲染和绘制页面。因此,任何关键资源都可能阻塞页面的首次渲染。关键请求链越大或越重,根据 Lighthouse 的评估,关键请求链对页面加载时间的影响就越大。

Critical request chain example

下载优先级是如何确定的

关键请求是在初始页面加载期间以高优先级下载的资源。这个优先级是如何确定的?

下载优先级由浏览器自身确定。浏览器遵循一组规则来确定每个资源的优先级。哪些元素最终获得最高优先级取决于页面的结构。浏览器认为对页面首次渲染必不可少的元素会被赋予最高优先级。

浏览器最初会对哪些元素最重要做出合理推测。一般来说,下载优先级的工作方式如下:HTML 始终具有最高优先级,然后是样式表、同步 JavaScript、字体、Ajax 请求、页面顶部的图片、页面后续的图片,最后是异步 JavaScript。

您可以自行查看页面上哪些资源被赋予了高优先级。使用 Ctrl + Shift + J 打开开发者控制台。导航到网络选项卡,右键单击列名并选择 'Priority'

Dev Console Resouce Priority

关键请求链如何影响页面加载时间?

加载页面时,浏览器以"显示阻塞"模式启动。在此模式下,最重要的资源以高优先级下载。这些就是关键资源。

浏览器在所有关键资源下载完成之前不会(完全)开始渲染页面。因此,任何关键资源都可能阻塞页面的首次渲染

页面的关键资源越少,浏览器将首屏内容显示到屏幕上所需的工作就越少,CPU 和其他资源的竞争也越小。

如何修复 Lighthouse 中的"避免链接关键请求"?

您可以通过三种方式减少关键请求的影响:

  1. 减少关键资源的数量。通过删除或延迟加载将关键资源转换为非关键资源。
  2. 减少关键字节数。这可能很明显,但减少关键路径资源的字节数可以使关键资源下载更快。例如通过 gzip 压缩、JavaScript tree shaking、图片优化或字体子集化。
  3. 优化关键路径的下载顺序。使用资源提示(如 preloading)来跳过资源发现过程,确保关键资源尽快下载。

有很多选项。哪个选项最好取决于资源的文件类型:

1. HTML

HTML 实际上就是您正在访问的页面,始终以最高优先级下载。页面本身始终是关键请求链的一部分。这就是为什么在优化关键请求链时,页面本身是首先要考虑的。

延迟加载内容:许多大型网站(如 Google 自身)使用此技术来减少关键请求链。例如在搜索结果页面上,不立即需要的部分内容仅在稍后通过 AJAX 请求加载。

压缩:更小总是更快,使用 HTML 压缩来移除页面中的注释、空格和空行。

压缩:最后,使用 Brotli 或 GZIP 压缩来正确压缩样式表非常重要

2. 样式表

页面头部的样式表始终是关键的。没有样式,浏览器不知道页面会是什么样子。因此,样式表是 Lighthouse 中关键请求链的标准组成部分。

关键 CSS:样式表可以通过一个简单的技巧变为非关键资源,即通过资源提示预加载样式表,并在预加载完成后将其添加为样式表。
在页面上添加以下代码:您的浏览器现在将以较低优先级下载样式表,并将 CSS 视为非渲染阻塞资源。它将在不等待 CSS 的情况下开始渲染。

<link rel="preload"
      href="css.css"
      type="text/css"
      as="style"
      onload="this.onload=null;this.rel='stylesheet';"/>

请注意,页面上现在会发生一些奇怪的事情。首先页面会显示出来,只有在加载 CSS 之后才会应用样式。所有内容将从无样式内容闪烁为有样式内容。我们可以用关键 CSS 来解决这个问题。
关键 CSS 是页面可见部分所需的所有 CSS 规则的集合。您可以通过 NodeJS 或一些在线工具生成关键 CSS。将这些关键 CSS 放在页面头部,其余 CSS 以较低优先级加载。

媒体查询:仅加载适用于您设备的样式。您的页面通常在移动设备上访问。因此,您实际上不需要下载桌面和打印的样式。这节省了时间,从而缩短了 Lighthouse 中的关键请求链。

使用 media 属性。media 属性确保仅在媒体与当前使用的媒体不匹配时才下载样式。

<link href="all.css" rel="stylesheet" media="all">
<link href="print.css" rel="stylesheet" media="print">
<link href="desktop.css" rel="stylesheet" media="screen and (min-device-width: 1024px)">

压缩移除未使用的 CSS。许多网站使用 CSS 库,如 bootstrap。这些库通常过于完整,并非所有样式声明都被使用。
通过 CSS 预处理器(如 SASS)可以轻松编辑这些库。只需通过更改应包含的内容来移除未使用的样式组,使它们更小。这些预处理器还提供了通过移除所有空格和换行来压缩 CSS 的选项。
">

压缩:最后,使用 Brotli 或 GZIP 压缩来正确压缩样式表非常重要

3. JavaScript

页面头部的 JavaScript 文件默认以高优先级下载,并在下载和执行过程中阻塞页面渲染。因此,JavaScript 是关键请求链的标准组成部分。

Defer 和 Async:通过 asyncdefer 属性异步加载来调整 JavaScript 文件的优先级。异步脚本文件以较低优先级并行下载。延迟加载的 JavaScript 也并行加载,且 JavaScript 的执行被延迟,因此 JavaScript 执行也不会阻塞页面的初始加载。

// blocks loading and execution
<script src="normalscript.js">
// async does not block during load, but it does block during execution
<script  src="asyncscript.js">
// defer does not block both during load nor execution
<script  src="deferscript.js">

代码拆分和预加载:如果页面不允许 JavaScript 异步加载,将 JavaScript 拆分为多个文件可能是个好主意。将页面加载期间关键的 JavaScript 部分放在一个小文件中并预加载此文件。将非关键 JavaScript 放在另一个文件中,让它延迟或异步加载和运行。

压缩:通过 JavaScript Uglyfier 工具以两种方式缩减字节数。这是一个智能工具,可以分析 JavaScript 并使其尽可能小。">

压缩:此外,通过 Gzip 或 Brotli 压缩 JavaScript 来减少字节数。

4. WebFonts

Web 字体通常是关键请求链中最后加载的文件。这是因为 Web 字体依赖于发现机制。它们只有在浏览器发现需要时才会加载。为此,浏览器必须首先分析 HTML 并在样式表中查找使用了哪种字体。

预加载:当您确定将依赖某种字体时,通常预加载该字体会更快。字体将尽早下载,这最大限度地减少了对关键请求链的影响。通过尽早在页面头部添加以下代码来预加载字体

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
字体策略:此外,还有许多其他方法可以使字体加载更快。
  • 始终依赖本地 Web 字体,而不是远程托管的字体(如 Google fonts)。
  • 通过字体子集化调整字体大小
  • 通过 JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/API/FontFace">fontface interface</a> 加载非关键字体
  • 使用 display = swap 以避免字体阻塞初始渲染
  • 通过字体合成让浏览器生成自己的字体变体

图片

页面加载期间出现在可见视口中的图片也可能被赋予高优先级,并可能干扰关键路径。当您确定某张图片始终会出现在网站的可见部分时,预加载该图片也可能很有用。

<link rel="preload" as="image" href="important-image.webp">

对于所有不立即可见的图片,为保险起见应延迟加载。使用 loading = "lazy" 来延迟图片的加载,直到图片即将可见。

<img loading="lazy" src="lazy-image.webp" width="20" height="20" alt="...">

5. AJAX 请求

AJAX 请求始终被分配高优先级。因此,最好将 AJAX 请求推迟到页面完成渲染之后。等待页面发送 "load" 事件。

如果无法推迟 AJAX 请求,您可以通过预加载来确保浏览器能够使用该 AJAX 请求。

window.addEventListener('load', (event)=>{
  console.log('this is a good time for an AJAX request');
});

6. iframes

Iframes 通常以高优先级下载。因为 iframe 实际上是页面中的页面,所以 iframe 可能会导致页面加载时间显著延迟。iframe 所需的资源也可能以高优先级下载并形成其自己的关键请求链。因此,使用 iframe 可能会显著影响您的 Lighthouse 分数。

您可以通过 loading = "lazy" 属性来延迟加载 iframe。当 iframe 在加载时不立即可见时,这通常会产生显著差异。通常通过 JavaScript 将 iframe 注入页面会更快。这使您可以更好地控制时机,以确保它不会进入关键请求链。

Stop debating in Jira.

Get a definitive answer on your performance issues. I deliver a granular breakdown of your critical rendering path.

Book a Deep Dive >>

  • Definitive Answers
  • Granular Breakdown
  • Critical Path Analysis
修复 Lighthouse 中的“避免链接关键请求”问题Core Web Vitals 修复 Lighthouse 中的“避免链接关键请求”问题