目录
目录
初始加载性能指标介绍
性能 DevTools 概述
项目设置
探索必要的 DevTools
探索 Lighthouse 面板
探索性能面板
附加练习
探索不同的网络条件
非常慢的服务器
模拟不同的带宽和延迟
CDN 的重要性
重复访问性能
使用 Cache-Control 头控制浏览器缓存
Cache-Control 和现代打包工具
我简单的用例真的需要了解所有这些吗?
首页 web前端 js教程 React 开发人员的初始负载性能:深入研究

React 开发人员的初始负载性能:深入研究

Jan 27, 2025 pm 06:33 PM

深入探讨网页首屏加载性能及优化策略

Initial load performance for React developers: investigative deep dive

目录

  1. 初始加载性能指标介绍
  2. 性能 DevTools 概述
    1. 项目设置
    2. 探索必要的 DevTools
  3. 探索不同的网络条件
    1. 非常慢的服务器
    2. 模拟不同的带宽和延迟
    3. CDN 的重要性
  4. 重复访问性能
    1. 使用 Cache-Control 头控制浏览器缓存
    2. Cache-Control 和现代打包工具
    3. 我简单的用例真的需要了解所有这些吗?

在 AI 驱动的代码生成蓬勃发展的今天,编写 React 代码的重要性正在下降。现在任何人和任何东西都可以用 React 编写应用程序。但是编写代码一直只是难题的一部分。我们仍然需要将我们的应用程序部署到某个地方,向用户展示它们,使它们健壮,使它们快速,并做一百万件其他事情。没有 AI 可以接管这些。至少现在还不行。

因此,让我们专注于今天如何使应用程序快速运行。为此,我们需要暂时离开 React。因为在使某些东西变快之前,我们首先需要知道“快”是什么,如何衡量它,以及什么可以影响这种“快”。

剧透警告:除了学习项目之外,本文不会出现 React。今天都是关于基础知识的:如何使用性能工具,Core Web Vitals 简介,Chrome 性能面板,初始加载性能是什么,哪些指标可以衡量它,以及缓存控制和不同的网络条件如何影响它。

初始加载性能指标介绍

当我打开浏览器并尝试导航到我喜欢的网站时会发生什么?我在地址栏中输入“https://www.php.cn/link/63ea3fef646010a7255aec506626ea32 GET 请求,并接收 HTML 页面作为返回。

Initial load performance for React developers: investigative deep dive

执行此操作所需的时间称为“Time To First Byte”(TTFB):从发送请求到结果开始到达之间的时间。接收 HTML 后,浏览器现在必须尽快将此 HTML 转换为可用的网站。

它首先在屏幕上渲染所谓的“关键路径”:可以向用户显示的最小和最重要的内容。

Initial load performance for React developers: investigative deep dive

关键路径中究竟应该包含什么是一个复杂的问题。理想情况下,一切都是为了让用户立即看到完整的体验。但是同样 - 什么也没有,因为它需要尽可能快,因为它是一条“关键”路径。两者同时是不可能的,所以需要妥协。

妥协是这样的。浏览器假设要构建“关键路径”,它绝对至少需要以下类型的资源:

  • 它从服务器接收的初始 HTML - 用于构建实际的 DOM 元素,从中构建体验。
  • 样式化这些初始元素的重要 CSS 文件 - 否则,如果它在不等待它们的情况下继续,用户会在一开始看到奇怪的未样式化内容“闪烁”。
  • 同步修改布局的关键 JavaScript 文件。

浏览器在服务器的初始请求中获取第一个(HTML)。它开始解析它,并在这样做的过程中提取它需要完成“关键路径”的 CSS 和 JS 文件的链接。然后,它发送请求以从服务器获取它们,等待它们下载完毕,处理它们,将所有这些组合在一起,并在某个时刻结束时,在屏幕上绘制“关键路径”像素。

由于浏览器在没有这些关键资源的情况下无法完成初始渲染,因此它们被称为“渲染阻塞资源”。当然,并非所有 CSS 和 JS 资源都是渲染阻塞的。通常只有:

  • 大多数 CSS,无论是内联的还是通过 标签。
  • 标签中不是异步或延迟的 JavaScript 资源。

渲染“关键路径”的整个过程大致如下所示:

  • 浏览器开始解析初始 HTML
  • 在此过程中,它从标签中提取 CSS 和 JS 资源的链接。
  • 然后,它启动下载过程并等待阻塞资源完成下载。
  • 在等待的同时,如果可能,它会继续处理 HTML。
  • 接收所有关键资源后,也会处理它们。
  • 最后,它完成需要完成的工作并绘制界面的实际像素。

这个时间点就是我们所说的首次绘制 (FP)。这是用户第一次有机会在屏幕上看到某些东西。是否会发生取决于服务器发送的 HTML。如果那里有一些有意义的东西,例如文本或图像,那么这一点也将是首次内容绘制 (FCP) 发生的时间。如果 HTML 只是一个空 div,那么 FCP 将稍后发生。

Initial load performance for React developers: investigative deep dive

首次内容绘制 (FCP) 是最重要的性能指标之一,因为它衡量的是感知到的初始加载。基本上,这是用户对您的网站速度的初步印象。

直到这一刻,用户只是在盯着空白屏幕咬指甲。根据 Google 的说法,良好的 FCP 数字是低于 1.8 秒。之后,用户将开始对您的网站可以提供的内容失去兴趣,并可能开始离开。

但是,FCP 并不完美。如果网站以旋转器或某些加载屏幕开始加载,则 FCP 指标将表示该内容。但用户不太可能只是为了查看花哨的加载屏幕而导航到该网站。大多数时候,他们想要访问内容。

为此,浏览器需要完成它开始的工作。它等待其余的非阻塞 JavaScript,执行它,将源自它的更改应用于屏幕上的 DOM,下载图像,并以其他方式完善用户体验。

在此过程中的某个时间点,就会发生最大内容绘制 (LCP) 时间。它不是像 FCP 那样非常第一个元素,而是页面上的主要内容区域 - 视口中可见的最大文本、图像或视频。根据 Google 的说法,这个数字理想情况下应该低于 2.5 秒。超过这个数字,用户会认为网站速度慢。

Initial load performance for React developers: investigative deep dive

所有这些指标都是 Google 的 Web Vitals 的一部分 - 一组代表页面上用户体验的指标。LCP 是三个核心 Web Vitals之一 - 三个指标代表用户体验的不同部分。LCP 负责加载性能

这些指标可以通过 Lighthouse 来衡量。Lighthouse 是 Google 的性能工具,它集成到 Chrome DevTools 中,也可以通过 shell 脚本、Web 界面或节点模块运行。您可以将其作为节点模块使用,以便在构建中运行它并在生产环境中出现回归之前检测到它们。使用集成的 DevTools 版本进行本地调试和测试。以及 Web 版本来检查竞争对手的性能。

性能 DevTools 概述

以上是对该过程的非常简短和简化的解释。但这已经有很多缩写和理论让人的头脑混乱。对我个人而言,阅读这样的内容是没有用的。除非我能看到它在行动中,并能亲自动手操作,否则我会立即忘记所有内容。

对于这个特定主题,我发现完全理解这些概念的最简单方法是在半真实的页面上模拟不同的场景,并查看它们如何改变结果。所以在进行更多理论(还有很多!)之前,让我们这样做。

项目设置

如果您愿意,您可以在您自己的项目上进行以下所有模拟 - 结果应该或多或少相同。但是,为了更受控制和简化的环境,我建议您使用我为本文准备的学习项目。您可以在这里访问它:https://www.php.cn/link/def14e8541708294d7558fdf2126ef27

首先安装所有依赖项:

<code>npm install</code>
登录后复制

构建项目:

<code>npm run build</code>
登录后复制

启动服务器:

<code>npm run start</code>
登录后复制

您应该在“https://www.php.cn/link/66e8d052ec2230c66bd11ee6b5a0e3c8

探索必要的 DevTools

在 Chrome 中打开要分析的网站并打开 Chrome DevTools。找到那里的“性能”和“Lighthouse”面板并将它们放在一起。我们需要两者。

此外,在本文中执行任何其他操作之前,请确保已启用“禁用缓存”复选框。它应该位于最顶部的“网络”面板中。

Initial load performance for React developers: investigative deep dive

这样我们就可以模拟首次访问者 - 从未访问过我们网站的人,并且浏览器还没有缓存任何资源。

探索 Lighthouse 面板

现在打开 Lighthouse 面板。您应该在那里看到一些设置和“分析页面加载”按钮。

Initial load performance for React developers: investigative deep dive

对于本节,我们感兴趣的是“导航”模式 - 它将对页面的初始加载进行详细分析。该报告将为您提供如下分数:

Initial load performance for React developers: investigative deep dive

本地性能完美无缺,这并不奇怪 - 一切都“在我的机器上运行”。

还会有如下指标:

Initial load performance for React developers: investigative deep dive

我们本文需要的 FCP 和 LCP 值就在顶部。

下面,您将看到一个可以帮助您提高分数的建议列表。

Initial load performance for React developers: investigative deep dive

每个建议都可以展开,您将在那里找到更详细的信息,有时还会找到解释该特定主题的链接。并非所有这些都可以采取行动,但它是一个开始学习性能并了解可以改进它的不同事物的绝佳工具。仅仅阅读这些报告和相关链接就可以花费数小时。

但是,Lighthouse 只提供表面信息,不允许您模拟慢速网络或低 CPU 等不同场景。它只是一个很好的切入点和一个跟踪性能随时间变化的绝佳工具。要更深入地了解正在发生的事情,我们需要“性能”面板。

探索性能面板

首次加载时,“性能”面板应如下所示:

Initial load performance for React developers: investigative deep dive

它显示了三个核心 Web Vitals 指标,其中一个是我们的 LCP,使您可以模拟慢速网络和 CPU,以及随着时间推移记录性能详细信息的能力。

在面板顶部找到并选中“屏幕截图”复选框,然后单击“记录并重新加载”按钮,当网站重新加载自身时 - 停止记录。这将是您对页面在初始加载期间发生情况的详细报告。

此报告将包含几个部分。

最顶部是常规的“时间轴概述”部分。

Initial load performance for React developers: investigative deep dive

您将在这里看到网站上正在发生某些事情,但没有更多内容。当您将鼠标悬停在其上时 - 将显示正在发生的事情的屏幕截图,并且您将能够选择并放大到特定范围以仔细查看。

在下面是网络部分。展开后,您将看到所有正在下载的外部资源以及它们在时间轴上的确切时间。当将鼠标悬停在特定资源上时,您将看到有关在下载的哪个阶段花费多少时间的详细信息。带有红色角的资源将指示阻塞资源。

Initial load performance for React developers: investigative deep dive

如果您正在使用学习项目,您将看到完全相同的图片,并且此图片与我们在上一节中逐字逐句进行的内容相匹配:

  • 一开始,有一个蓝色块 - 获取网站 HTML 的请求
  • 加载完成后,稍作暂停(解析 HTML),两个获取更多资源的请求发出。
  • 其中一个(黄色)用于 JavaScript - 非阻塞。
  • 另一个(紫色)用于 CSS,这是一个阻塞。

如果您现在打开您的学习项目代码并查看 dist 文件夹,源代码将与这种行为相匹配:

  • 将有一个 index.html 文件和 assets 文件夹中的 .css 和 .js 文件
  • 在 index.html 文件中的部分中,将有一个 标签指向 CSS 文件。正如我们所知, 标签中的 CSS 资源是渲染阻塞的,所以这可以检查出来。
  • 此外,在其中还有一个 <script> 标签指向 asset 文件夹中的 JavaScript 文件。它既不是延迟的也不是异步的,但它具有 type="module"。这些是自动延迟的,所以这也检查出来了 - 面板中的 JavaScript 文件是非阻塞的。</script>

附加练习

如果您正在处理某个项目,请记录其初始加载性能并查看“网络”面板。您可能会看到更多正在下载的资源。

  • 您有多少个渲染阻塞资源?所有这些都是必要的吗?
  • 您知道项目的“入口”点在哪里以及阻塞资源如何在 <script> 部分中出现吗?尝试使用您的 npm build 变体构建项目并搜索它们。提示:- 如果您有一个纯基于 webpack 的项目,请查找 webpack.config.js 文件。HTML 入口点的路径应该在里面。</script>
  • 如果您使用 Vite,请查看 dist 文件夹 - 与学习项目相同
  • 如果您使用 Next.js App 路由器 - 请查看 .next/server/app

在“网络”部分下,您可以找到“帧”和“计时”部分。

Initial load performance for React developers: investigative deep dive

这些非常酷。在“计时”部分,您可以看到我们之前讨论过的所有指标(FP、FCP、LCP),以及我们尚未讨论的一些指标。当将鼠标悬停在指标上时,您可以看到它花费的确切时间。单击它们将更新最底部的“摘要”选项卡,您将在其中找到有关此指标的信息和了解更多信息的链接。DevTools 现在都是关于教育人们的。

最后是部分。这是在记录的时间轴期间在主线程中发生的事情。

Initial load performance for React developers: investigative deep dive

我们在这里可以看到诸如“解析 HTML”或“布局”之类的内容以及它花费了多长时间。黄色部分与 JavaScript 相关,它们有点没用,因为我们使用的是带有压缩 JavaScript 的生产版本。但即使在这种状态下,它也能让我们大致了解 JavaScript 执行与 HTML 解析和绘制布局相比需要多长时间,例如。

网络都打开并放大以占据整个屏幕时,它对于性能分析尤其有用。

Initial load performance for React developers: investigative deep dive

从这里,我可以看出我的服务器速度非常快,捆绑包也很快很小。没有一个网络任务是瓶颈;它们不需要任何大量时间,它们之间,浏览器只是在闲逛并做它自己的事情。因此,如果我想在这里加快初始加载速度,我需要研究为什么“解析 HTML”这么慢 - 它是图表上最长的任务。

或者,如果我们查看绝对数字 - 我不应该在这里做任何事情,从性能方面来说。整个初始加载时间少于 200 毫秒,远低于 Google 建议的阈值?但这正在发生,因为我是在本地运行此测试(因此没有实际的网络成本),在一台非常快的笔记本电脑上,并且使用非常基本的服务器。

是时候模拟现实生活了。

探索不同的网络条件

非常慢的服务器

首先,让我们使服务器更逼真。现在,第一个“蓝色”步骤大约需要 50 毫秒,其中 40 毫秒只是在等待。

Initial load performance for React developers: investigative deep dive

在现实生活中,服务器将执行某些操作,检查权限,生成某些内容,再次检查权限(因为它有很多遗留代码,并且三遍检查丢失了),否则将很忙。

导航到学习项目中的 backend/index.ts 文件 (https://www.php.cn/link/def14e8541708294d7558fdf2126ef27)。找到注释掉的 // await sleep(500),并取消注释它。这将使服务器在返回 HTML 之前延迟 500 毫秒 - 这对于旧的复杂服务器来说似乎足够合理。

重新构建项目 (npm run build),重新启动它 (npm run start) 并重新运行性能记录。

除了初始蓝线之外,时间轴上没有任何变化 - 与其余内容相比,它现在非常长。

Initial load performance for React developers: investigative deep dive

这种情况突出了在进行任何性能优化之前查看全局并识别瓶颈的重要性。LCP 值约为 650 毫秒,其中约 560 毫秒用于等待初始 HTML。它的 React 部分约为 50 毫秒。即使我设法将其减半并将其减少到 25 毫秒,在整体情况中,它也只有 4%。而将其减半将需要大量的努力。更有效的策略可能是专注于服务器并找出它为什么这么慢。

模拟不同的带宽和延迟

并非每个人都生活在 1 千兆位连接的世界中。例如,在澳大利亚,50 兆位/秒是高速互联网连接之一,每月将花费您约 90 澳元。当然,它不是 3G,全世界很多人都被困住了。但仍然,每次我听到欧洲人吹嘘他们的 1 千兆位/秒或 10 欧元的互联网计划时,我都会哭泣。

无论如何。让我们模拟这个不太好的澳大利亚互联网,看看性能指标会发生什么。为此,清除性能选项卡中的现有记录(重新加载和记录按钮附近的按钮)。网络设置面板应该显示出来:

Initial load performance for React developers: investigative deep dive

如果它没有出现在您的 Chrome 版本中,则相同的设置应该在“网络”选项卡中可用。

在“网络”下拉菜单中添加一个新的配置文件,使用以下数字:

  • 配置文件名称:“平均互联网带宽”
  • 下载:50000(50 Mbps)
  • 上传:15000(15 Mbps)
  • 延迟:40(一般互联网连接的平均值)

Initial load performance for React developers: investigative deep dive

现在在下拉菜单中选择该配置文件并再次运行性能记录。

你看到了什么?对我来说,它看起来像这样。

LCP 值几乎没有变化 - 从 640 毫秒略微增加到 700 毫秒。初始蓝色“服务器”部分没有任何变化,这是可以解释的:它只发送最基本的 HTML,因此下载它不应该花费很长时间。

但是可下载资源和主线程之间的关系发生了巨大变化。

Initial load performance for React developers: investigative deep dive

我现在可以清楚地看到渲染阻塞 CSS文件的影响。“解析 HTML”任务已经完成,但浏览器正在闲置并等待 CSS - 在下载之前无法绘制任何内容。将其与之前的图片进行比较,在之前的图片中,资源几乎是即时下载的,而浏览器正在解析 HTML。

之后,从技术上讲,浏览器本可以绘制某些内容 - 但没有任何内容,我们只在 HTML 文件中发送一个空 div。因此,浏览器继续等待,直到下载并执行 javascript 文件。

这个大约 60 毫秒的等待差距正是我看到的 LCP 的增加。

进一步降低速度以查看它的进展情况。创建一个新的网络配置文件,将其命名为“低互联网带宽”,从“低互联网带宽”配置文件复制下载/上传数字,并将延迟设置为 40 毫秒。

Initial load performance for React developers: investigative deep dive

并再次运行测试。

LCP 值现在已增加到近 500 毫秒。JavaScript 下载大约需要 300 毫秒。相对而言,“解析 HTML”任务和 JavaScript 执行任务的重要性正在减小。

Initial load performance for React developers: investigative deep dive

附加练习

如果您有自己的项目,请尝试在其上运行此测试。

  • 下载所有关键路径资源需要多长时间?
  • 下载所有 JavaScript 文件需要多长时间?
  • 此下载在“解析 HTML”任务之后会导致多大的差距?
  • 在主线程中,“解析 HTML”和 JavaScript 执行任务相对于资源下载有多大?
  • 它如何影响 LCP 指标?

资源栏内部发生的事情也很有趣。将鼠标悬停在黄色 JavaScript 条上。您应该在那里看到类似这样的内容:

Initial load performance for React developers: investigative deep dive

这里最有趣的部分是“发送请求并等待”,大约需要 40 毫秒。将鼠标悬停在其余的网络资源上 - 所有这些都将拥有它。那是我们的延迟,我们设置为 40 的网络延迟。许多事情都会影响延迟数字。网络连接的类型就是其中之一。例如,平均 3G 连接的带宽为 10/1 Mbps,延迟在 100 到 300 毫秒之间。

要模拟这一点,请创建一个新的网络配置文件,将其命名为“平均 3G”,从“低互联网带宽”配置文件复制下载/上传数字,并将延迟设置为 300 毫秒。

再次运行分析。所有网络资源的“发送请求并等待”都应增加到大约 300 毫秒。这将进一步推动 LCP 数字:对我来说是1.2 秒

现在是有趣的部分:如果我将带宽恢复到超高速但保持低延迟会发生什么?让我们尝试此设置:

  • 下载:1000 Mbps
  • 上传:100 Mbps
  • 延迟:300 毫秒

如果您的服务器位于挪威某个地方,而客户端是富有的澳大利亚人,则很容易发生这种情况。

这是结果:

Initial load performance for React developers: investigative deep dive

LCP 数字约为960 毫秒。它比我们之前尝试过的最慢的互联网速度还要差!在这种情况下,捆绑包大小并不重要,CSS 大小根本不重要。即使您将两者都减半,LCP 指标也几乎不会移动。高延迟胜过一切。

这让我想到了每个人都应该实现的第一个性能改进,如果他们还没有实现的话。它被称为“确保静态资源始终通过 CDN 提供服务”。

CDN 的重要性

CDN(内容分发网络)基本上是任何前端性能相关工作的第 0 步,甚至在开始考虑更花哨的东西(如代码分割或服务器组件)之前。

任何 CDN(内容分发网络)的主要目的是减少延迟并尽快将内容交付给最终用户。它们为此实施了多种策略。本文最重要的两个是“分布式服务器”和“缓存”。

CDN 提供商将在不同的地理位置拥有多个服务器。这些服务器可以存储静态资源的副本,并在浏览器请求它们时将它们发送给用户。CDN 基本上是您原始服务器周围的一个软层,可以保护它免受外部影响并最大限度地减少它与外部世界的交互。它有点像内向者的 AI 助手,它可以在无需让真人参与的情况下处理典型的对话。

在上面的示例中,我们的服务器位于挪威,客户端位于澳大利亚,我们有这样的图片:

Initial load performance for React developers: investigative deep dive

有了中间的 CDN,图片就会改变。CDN 将在更靠近用户的地方拥有一个服务器,例如,也在澳大利亚某个地方。在某个时刻,CDN 将从原始服务器接收静态资源的副本。之后,来自澳大利亚或附近任何地方的用户都将获得这些副本,而不是来自挪威服务器的原始副本。

它实现了两个重要的事情。首先,原始服务器上的负载减少了,因为用户不再需要直接访问它。其次,用户现在可以更快地获得这些资源,因为他们不再需要跨越海洋来下载一些 JavaScript 文件了。

Initial load performance for React developers: investigative deep dive

而我们上面模拟中的 LCP 值从960 毫秒下降到 640 毫秒?

重复访问性能

到目前为止,我们只讨论了首次访问性能 - 从未访问过您网站的人的性能。但希望该网站如此出色,以至于大多数首次访问者都会变成常客。或者至少他们在第一次加载后不会离开,浏览几个页面,也许会购买一些东西。在这种情况下,我们通常期望浏览器缓存静态资源(如 CSS 和 JS)- 即在本地保存它们的副本,而不是总是下载它们。

让我们看看在这种情况下性能图表和数字如何变化。

再次打开学习项目。在开发工具中,将“网络”设置为我们之前创建的“平均 3G” - 具有高延迟和低带宽,这样我们就可以立即看到差异。并确保“禁用网络缓存”复选框未选中。

Initial load performance for React developers: investigative deep dive

首先,刷新浏览器以确保我们正在消除首次访问者的情况。然后刷新并测量性能。

如果您使用的是学习项目,最终结果可能会有些令人惊讶,因为它看起来像这样:

Initial load performance for React developers: investigative deep dive

CSS 和 JavaScript 文件在网络选项卡中仍然非常突出,我看到它们在“发送请求并等待”中大约有 300 毫秒 - 我们在“平均 3G”配置文件中设置的延迟设置。结果,LCP 并不像它可能的那样低,并且当浏览器只是等待阻塞 CSS 时,我有一个 300 毫秒的差距。

发生了什么?浏览器不应该缓存这些东西吗?

使用 Cache-Control 头控制浏览器缓存

我们现在需要使用“网络”面板来了解发生了什么。打开它并在那里找到 CSS 文件。它应该如下所示:

Initial load performance for React developers: investigative deep dive

这里最有趣的是“状态”列和“大小”。在“大小”中,它绝对不是整个 CSS 文件的大小。它太小了。在“状态”中,它不是我们通常的 200“一切正常”状态,而是不同的东西 - 304 状态。

这里有两个问题 - 为什么是 304 而不是 200,以及为什么根本发送了请求?为什么缓存不起作用?

首先,304 响应。这是一个配置良好的服务器为条件请求发送的响应 - 其中响应根据各种规则而变化。此类请求经常用于控制浏览器缓存。

例如,当服务器接收到 CSS 文件的请求时,它可以检查上次修改文件的时间。如果此日期与浏览器端缓存文件中的日期相同,则它将返回带有空正文的 304(这就是为什么它只有 223 B)。这表示浏览器可以安全地重新使用它已经拥有的文件。无需浪费带宽并再次重新下载它。

这就是为什么我们在性能图片中看到很大的“发送请求并等待”数字 - 浏览器要求服务器确认 CSS 文件是否仍然是最新的。这就是为什么那里的“内容下载”是 0.33 毫秒 - 服务器返回“304 未修改”,浏览器只是重新使用了之前下载的文件。

附加练习

  1. 在学习项目中,转到 dist/assets 文件夹并重命名 CSS 文件
  2. 转到 dist/index.html 文件并更新重命名 CSS 文件的路径
  3. 刷新已打开的页面并打开“网络”选项卡,您应该看到 CSS 文件以新名称、200 状态和正确的大小出现 - 它已再次下载。这被称为“缓存清除” - 一种强制浏览器重新下载它可能已缓存的资源的方法。
  4. 再次刷新页面 - 它已返回到 304 状态并重新使用缓存的文件。

现在,对于第二个问题 - 为什么根本发送了这个请求?

此行为由服务器设置为响应的 Cache-Control 标头控制。单击“网络”面板中的 CSS 文件以查看请求/响应的详细信息。在“标头”选项卡的“响应标头”块中查找“Cache-Control”值:

Initial load performance for React developers: investigative deep dive

在此标头内,可以以不同的组合组合多个指令,用逗号分隔。在我们的例子中,有两个:

  • max-age 带有一个数字 - 它控制此特定响应将存储多长时间(以秒为单位)
  • must-revalidate - 它指示浏览器如果响应已过期,则始终向服务器发送新鲜版本的请求。如果响应在缓存中存在的时间超过 max-age 值,则响应将过期。

因此,基本上,此标头告诉浏览器:

  • 可以将此响应存储在您的缓存中,但过一段时间后要再次与我核实。
  • 顺便说一句,您可以保留该缓存的时间正好是秒。祝你好运。

结果,浏览器总是与服务器核实,并且从不立即使用缓存。

但是,我们可以很容易地改变这一点 - 我们只需要将 max-age 数字更改为 0 到 31536000(一年,允许的最大秒数)之间即可。为此,在您的学习项目中,转到 backend/index.ts 文件,找到设置 max-age=0 的位置,并将其更改为 31536000(一年)。刷新页面几次,您应该在“网络”选项卡中看到 CSS 文件的以下内容:

Initial load performance for React developers: investigative deep dive

请注意,现在“状态”列已变灰,对于“大小”,我们看到“(内存缓存)”。CSS 文件现在从浏览器的缓存中提供服务,并且一年内将一直如此。刷新页面几次以查看它不会更改。

现在,对于处理缓存标头的全部要点:让我们再次测量页面的性能。不要忘记设置“平均 3G”配置文件设置并保持“禁用缓存”设置未选中。

结果应该类似于:

Initial load performance for React developers: investigative deep dive

尽管延迟很高,“发送请求并等待”部分几乎减少到零,“解析 HTML”和 JavaScript 评估之间的差距几乎消失了,我们的 LCP 值又回到了 ~650 毫秒。

附加练习

  1. 将 max-age 值更改为 10(10 秒)
  2. 选中“禁用缓存”复选框并刷新页面以删除缓存。
  3. 取消选中复选框并再次刷新页面 - 这次应该从内存缓存中提供服务。
  4. 等待 10 秒,然后再次刷新页面。因为 max-age 只有 10 秒,所以浏览器将再次检查资源,服务器将再次返回 304。
  5. 立即刷新页面 - 它应该再次从内存中提供服务。

Cache-Control 和现代打包工具

上述信息是否意味着缓存是我们的性能灵丹妙药,我们应该尽可能积极地缓存所有内容?绝对不是!除了其他一切之外,创建“不精通技术的客户”和“需要通过电话解释如何清除浏览器缓存”的组合的可能性将导致最资深的开发人员出现恐慌性发作。

有数百万种优化缓存的方法,数百万种在 Cache-Control 标头中的指令与其他可能或可能不会影响缓存持续时间的标头的组合,这也可能或可能不取决于服务器的实现。可能仅关于此主题本身就可以编写几本书的信息。如果您想成为缓存大师,请从https://web.dev/和 MDN 资源上的文章开始,然后按照面包屑进行操作。

不幸的是,没有人能告诉你,“这是适用于所有内容的五种最佳缓存策略”。充其量,答案可能是:“如果您有这个用例,结合这个、这个和这个,那么这个缓存设置组合是一个不错的选择,但要注意这些问题”。这一切都归结于了解您的资源、构建系统、资源更改的频率、缓存的安全性以及错误操作的后果。

但是,有一个例外。一种例外,即存在明确的“最佳实践”:使用现代工具构建的网站的 JavaScript 和 CSS 文件。现代打包工具(如 Vite、Rollup、Webpack 等)可以创建“不可变”的 JS 和 CSS 文件。它们当然不是真正“不可变”的。但是这些工具使用依赖于文件内容的哈希字符串生成文件名称。如果文件内容发生更改,则哈希会更改,文件名称也会更改。结果,当网站部署时,无论缓存设置如何,浏览器都将重新获取文件的全新副本。缓存已“清除”,就像我们之前手动重命名 CSS 文件时一样。

例如,查看学习项目中的 dist/assets 文件夹。JS 和 CSS 文件都有 index-[hash] 文件名。记住这些名称并运行 npm run build 几次。名称保持不变,因为这些文件的内容没有改变。

现在转到 src/App.tsx 文件并在某个地方添加类似 console.log('bla') 的内容。再次运行 npm run build 并检查生成的文件。您应该看到 CSS 文件名保持不变,但 JS 文件名已更改。当此网站部署时,下次重复用户访问它时,浏览器将请求一个在其缓存中从未出现过的完全不同的 JS 文件。缓存已清除。

附加练习

查找项目的 dist 文件夹的等效项并运行您的构建命令。

  • 文件名是什么样的?类似于哈希,还是普通的 index.js、index.css 等?
  • 当您再次运行构建命令时,文件名是否会更改?
  • 如果您在代码中的某个位置进行简单的更改,有多少文件名会更改?

如果您的构建系统就是这样配置的 - 您很幸运。您可以安全地配置服务器以设置生成资产的最大 max-age 标头。如果您同样对所有图像进行版本控制 - 更好的是,您还可以将图像包含到列表中。

根据网站及其用户及其行为,这可能会为您免费提供初始加载的相当不错的性能提升。

我简单的用例真的需要了解所有这些吗?

此时,您可能正在想类似这样的事情,“你疯了。我周末用 Next.js 构建了一个简单的网站,并在 2 分钟内将其部署到 Vercel/Netlify/HottestNewProvider。当然,这些现代工具会为我处理所有这些。”这很公平。我也这么认为。但后来我实际上检查了一下,哇,我很惊讶?

我的两个项目对 CSS 和 JS 文件都有 max-age=0 和 must-revalidate。事实证明,这是我的 CDN 提供商的默认设置??‍♀️。当然,他们有理由

以上是React 开发人员的初始负载性能:深入研究的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

<🎜>:泡泡胶模拟器无穷大 - 如何获取和使用皇家钥匙
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系统,解释
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆树的耳语 - 如何解锁抓钩
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1672
14
CakePHP 教程
1428
52
Laravel 教程
1332
25
PHP教程
1276
29
C# 教程
1256
24
Python vs. JavaScript:学习曲线和易用性 Python vs. JavaScript:学习曲线和易用性 Apr 16, 2025 am 12:12 AM

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

从C/C到JavaScript:所有工作方式 从C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript和Web:核心功能和用例 JavaScript和Web:核心功能和用例 Apr 18, 2025 am 12:19 AM

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

JavaScript在行动中:现实世界中的示例和项目 JavaScript在行动中:现实世界中的示例和项目 Apr 19, 2025 am 12:13 AM

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

了解JavaScript引擎:实施详细信息 了解JavaScript引擎:实施详细信息 Apr 17, 2025 am 12:05 AM

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python vs. JavaScript:社区,图书馆和资源 Python vs. JavaScript:社区,图书馆和资源 Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

Python vs. JavaScript:开发环境和工具 Python vs. JavaScript:开发环境和工具 Apr 26, 2025 am 12:09 AM

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。

C/C在JavaScript口译员和编译器中的作用 C/C在JavaScript口译员和编译器中的作用 Apr 20, 2025 am 12:01 AM

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

See all articles