程序猿东哥

V1

2022/12/03阅读:47主题:全栈蓝

【第四期】如何优化LCP

前言

在上一篇一起探讨了RAIL模型中的核心指标LCP,了解了什么是LCP,为什么LCP指标对用户访问我们的网页来说比较重要。既然这个指标在性能模型中是比较重要的,那么我们该如何去优化他呢,文本就一起来探讨如何优化LCP指标。

首先我们来看看从用户开始敲下浏览器地址开始,到统计LCP指标的大致时间轴

从上面的时间轴就可以看出,对于优化LCP指标,我们可以大致分为几个部分:优化服务响应速度、优化首屏资源加载、优化首屏内容渲染。所以下面我们就这几个部分分别来看看如何去优化?

优化服务响应时间(TTFB)

浏览器到服务器请求内容过程,其实就是浏览器像服务请求内容,服务接收到请求后给出响应内容,浏览器在接收内容的过程,这个指标也就是首字节时间(Time to Fisrt Byte)。这个过程一般会从一下几个方面进行优化

  • 优化服务器
  • 将用户路由到附近的 CDN
  • 服务器缓存内容
  • 浏览器缓存 HTML 页面
  • 尽早建立第三方连接

优化服务器

如果我们访问的地址是ssr方式进行返回页面内容,需要考虑生成内容的时间。例如需要排查是否正在运行需要消耗大量时间和系统资源才能完成的查询?或者服务器端是否有其他复杂的操作会延迟页面内容的返回过程?分析和提高服务器端代码的效率将直接改善浏览器接收数据所需的时间。

如果是ssr情况下,服务器端网络框架并不会在浏览器请求时立即提供静态页面,而是需要动态创建网络页面。也就是说,框架并不会在浏览器请求时发送一个已经准备好的完整 HTML 文件,而是需要运行逻辑来构建页面。所以我们要关注在服务器上运行的性能问题,从这方面来有优化服务端响应时间,您可以利用这些优化来加快访问速度。

将用户路由到附近的CDN

如果我们提供的内容是比较静态的或者不常更新的内容,可以把我们提供的内容放在CDN上。内容分发网络 (CDN) 是分布在许多不同位置的服务器网络。如果将网页内容托管在单个服务器上,那么对于地理位置较远的用户来说,网站加载速度就会变慢,因为他们的浏览器请求不得不跨越千山万水。所以我们可以考虑使用 CDN 来确保您的用户永远不必为发送到远距离服务器的网络请求而等待。当然要考虑我们提供的内容的实际情况,如果内容放到cdn上,那需要做一些更新策略。

服务器缓存内容

如果我们提供的 HTML 是静态的,且不需要针对每个请求进行更改,那么缓存可以防止网页进行不必要的重建。通过在磁盘上存储已生成 HTML 的副本,服务器端缓存可以减少 TTFB 并最大限度地减少资源使用。

有许多不同的方法可以进行服务器缓存:

  • 配置反向代理(Varnish、nginx)来提供缓存内容,或者当安装在应用程序服务器之前时充当缓存服务器
  • 配置和管理您的云服务提供商的缓存行为
  • 使用提供边缘服务器的 CDN,以便将您的内容进行缓存并存储在离您的用户更近的地方

浏览器缓存 HTML 页面

如果我们提供的内容,访问量比较大,内容在短时间内容不会变动,可以利用浏览器的service worker来缓存一定时间的HTML内容。安装好的 Service Worker 会在浏览器后台运行,并可以拦截来自服务器的请求。此级别的程序化缓存控制使得缓存部分或全部 HTML 页面内容得以实现,并且只会在内容发生更改时更新缓存。

下方的图表显示使用该模式能够减少网站的 LCP 分布:

该图表显示了过去 28 天内某个网站的 LCP 分布,并且按 Service Worker 状态进行了细分。请注意,在 Service Worker 中引入优先使用缓存的 HTML 页面服务后,大多数页面加载的 LCP 值都变得更为迅速(图表的蓝色部分)。

当然这中策略,需要看提供的内容是不是用户每次访问是实时变化的,如果是实时变化这种意义就没那么大,这种适合在一定时间内不会发生变化,可以考虑这种模式来优化。

尽早建立第三方连接

对第三方域名的服务器请求也会影响 LCP,尤其是当浏览器需要这些请求来在页面上显示关键内容的情况下。使用rel="preconnect"来告知浏览器我们的页面打算尽快建立连接。

<link rel="preconnect" href="https://example.com" />

还可以使用dns-prefetch来更快地完成 DNS 查找。

<link rel="dns-prefetch" href="https://example.com" />

尽管两种提示的原理不同,但对于不支持preconnect的浏览器,可以考虑将dns-prefetch做为后备。

<head>
  …
  <link rel="preconnect" href="https://example.com" />
  <link rel="dns-prefetch" href="https://example.com" />
</head>

优化首屏资源加载

我们都知道浏览器在渲染之前,会把我们从服务器端加载内容解析成DOM结构树,如果 HTML 解析器遇到任何外部样式表(<link rel="stylesheet">)或同步 JavaScript 标签(<script src="main.js">),则会暂停解析。

所以脚本和样式表都是阻塞渲染的资源,这些资源会使 FCP 延迟,进而导致 LCP 延迟。延迟加载任何非关键的 JavaScript 和 CSS,从而提高网页主要内容的加载速度。

减少CSS样式的阻塞时间

我们可以通过压缩CSS大小、延迟加载非首屏css、重要的css进行内联等这些方式来减少css的阻塞时间,让首屏内容尽快进行渲染

压缩CSS

为了更加易于阅读,CSS 文件可以包含空格、缩进或注释等字符。这些字符对于浏览器来说都不是必要的,而对这些文件进行削减能够确保将这些字符删除。最终,在减少了阻塞渲染的 CSS 数量后,充分渲染页面主要内容所需的时间 (LCP) 也总是能够相应地缩短。

如果使用模块打包器或构建工具,那么可以在其中包含一个相应的插件来在每次构建时削减 CSS 文件,对于 webpack一般都是用optimize-css-assets-webpack-plugin插件来压缩css

LCP 改进示例:削减 CSS 前后对比

延迟加载非首屏CSS

如果是在您网站的单独页面上使用,可以将所有未使用的 CSS 完全删除或移动到另一个样式表。对于任何初始渲染时不需要的 CSS,可以使用异步加载文件。

LCP 改进示例:延迟加载非关键 CSS 前后对比

重要的css进行内联

通过把用于首屏内容的任何关键路径 CSS 直接包括在<head>中来将这些 CSS 进行内联。

将重要样式进行内联后,就不再需要通过往返请求来获取关键 CSS。延迟加载其余部分可以最大限度地减少 CSS 阻塞时间。

减少JS的阻塞时间

加载并向用户提供尽可能少的必要 JavaScript。减少阻塞渲染的 JavaScript 数量能够让渲染速度更快,从而获得更好的 LCP。一般会采用:精简内容和压缩 JavaScript 文件、延迟加载未使用的 JavaScript、最大限度减少未使用的 polyfill

优化其他资源加载

虽然 CSS 或 JavaScript 阻塞时间的增加会直接导致性能下降,但加载许多其他类型资源所需的时间也会影响绘制时间。前一篇文章我们讲到了影响 LCP 的元素类型为:<img>元素、内嵌在<svg>元素内的<image>元素、<video>元素、通过url()函数(而非使用 CSS 渐变)加载的带有背景图像的元素、包含文本节点或其他行内级文本元素的块级元素。如果在首屏渲染,加载这些元素所需的时间将对 LCP 产生直接影响。

所以我们一般会采用如下的方法来优化这些内容:

  • 优化和压缩图像
  • 压缩文本文件
  • 使用 Service Worker 缓存内容

优化首屏内容渲染

如果我们的页面不是采用ssr的方式来渲染,采用的csr的方式。这就需要我们优化客户端渲染的性能。所以我们应该特别关注大型 JS 包时可能对 LCP 产生的影响,因为在所有关键 JavaScript 完成下载和执行前,用户可能都无法看到页面上的任何内容或与之交互。

所以我们的优化策略除了前面我们提到的资源加载问题外,还需要我们从一下几个方面来优化我们的渲染:

  • 尽可能在渲染时减少非必要的资源加载
  • 在渲染时避免执行较长的任务
  • 避免渲染产生较元素大抖动

小结

以上就是我们本文聊到的一些关于LCP的具体优化策略,从三个阶段来进行优化,其实每一部分还是可以继续研究的。 我们在做完自己的产品后,可以用工具来检验一下网页的LCP时长如何,看看哪些阶段还有优化。一般验证工具有chrome开发者工具里面的preformance和其他工具(lighthouse)。

分类:

前端

标签:

前端

作者介绍

程序猿东哥
V1