第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定

Preply如何優(yōu)化主頁(yè)和搜索頁(yè)面的INP指標(biāo)(不用React服務(wù)端組件和App Router)

Two Peply.com’s pages visited from mobile devices, along with the screenshots of some performance deshboards.

为了从SEO和SEM的角度提升我们两个最重要的页面,我们开始研究如何提高它们的INP,这是一个衡量用户与页面互动速度的指标。这是一项由明确目标驱动的研发项目,这个目标基于大量的数据和假设。我们花费了很多时间来确定需要优化的内容,并进行了一行行的改动和大规模的重构。我们尝试了React Server Components和Next.js的新App Router。我们成功了,但也经常失败。在这篇文章中,我们将分享整个旅程和一些心得。

前言
为什么在意网页速度?

网页加载速度很重要,因为:

  1. 从SEO的角度来看,页面速度是搜索引擎的排名因素
  2. 从SEM的角度来看,页面速度会影响你在像Google Ads这样的平台上的质量得分。更高的质量得分会带来更低的每次点击成本(CPC),并且广告排名也会更靠前。
  3. 从用户的角度来看,更快的页面速度能带来更好的用户参与度和更高的转化率。

Preply.com 是一个面向消费者和企业的在线辅导平台,因此SEO和SEM的优化是我们日常工作的一部分。页面加载速度影响了我们在这两方面的SEO和SEM优化效果。页面速度通过量化网站用户体验来衡量,它通过 Web Vitals 进行衡量。其中一个 核心 Web Vitals 是 INP,它也是 Preply.com 最差的核心 Web Vital。

INP是什么?(注:请参见后续文本以了解INP的详细信息。)

官方定义的 INP (Interaction to Next Paint) 为:

INP 是一个衡量页面整体响应用户交互的指标,通过观察用户访问页面过程中所有点击、触摸和键盘交互的响应时间来实现。最终的 INP 值是所观察到的最长交互,忽略异常情况。

实际上,我们可以简单地说,一个“普通的”多页应用是这样的:

  1. 用户访问了一个网页,并与该网页进行了交互。
  2. INP 以毫秒为单位测量交互后执行的所有同步 JavaScript 代码。
  3. 这个最长交互即为该网页在此用户会话中的 INP。
  4. 整个页面的 INP 是过去 28 天内,通过桌面和移动设备的会话记录计算得出的 INP 的 75 百分位数。

几点需要注意的关键事项:

  1. 用户在网页上的行为并不重要。有些人会关闭隐私横幅,有些人则会在一个页面上花费15分钟做很多事情。最慢的交互是他们的INP。
  2. 用户并没有我们通常用来开发数字产品的那种高端设备。对于移动设备来说,有些用户用的是非常老旧且运行速度很慢的智能手机(这种情况的数量在很大程度上取决于你所在的市场)。因此,你的用户可能在处理一些你未曾意识到的性能问题。设备越慢,INP就越糟糕

感谢近期的 Google Chrome 更新,现在本地使用 INP 非常简单,看看以下 devtools 的性能选项卡中的截图,可以看到其中包含的 INP。

The Google Chrome devtools’s Performance tab shows the Core Web Vitals for the current session, especially INP, and the slowest interaction that caused it.

谷歌 Chrome 开发工具的“性能”标签显示了当前的 session 的核心 Web 指标,特别是 INP,以及造成这种情况的最慢一次互动。

Preply.com的技术堆栈

所有 Preply.com 的被索引页面都是通过一个多页面的 Next.js 13 应用程序(React 18)通过 Pages 路由器在服务器上进行渲染来管理的。代码库庞大且积累了大量技术债。

Next.js应用程序有数千个索引页面,但从SEO和SEM的角度来看,最重要的两个页面分别是首页和搜索页面。这两个页面有很大的不同:

  1. 首页的代码很少,大部分内容是静态的。唯一的互动元素是一个滑块和隐私政策提示条。
  2. 搜索页面庞大且复杂,其中90%的内容是互动的,包括用于筛选导师和预订课程的模态对话框。

两个页面的Web Vitals还算不错,但在移动设备的交互延迟(INP)方面仍有改进空间。项目的目标是将交互延迟从黄色等级提升到绿色等级。

Our internal dashboard reports the INP for the Home page \(~250 ms before the optimizations, 185 ms after the optimizations\) and the Search page \(~250 ms before the optimizations, 175 ms after the optimizations\).

我们内部的仪表板显示了主页的INP从优化前的约250毫秒优化到了约185毫秒,以及搜索页面的INP从优化前的约250毫秒优化到了约175毫秒。这里的INP指的是输入延迟。

我们估算出将两个名为INP的页面移动到绿色区域内的页面可以每年为我们省下约20万美元。请注意,这只是我们基于分析当前的SEO情况、竞争对手网站的Web Vitals以及估算这些方面的改进空间后得出的一个粗略数字。

我们的最初假设

我们主要有两个想法,关于我们如何改进INP(INP指代具体事项):

  1. 我们需要减少 React 的 hydration,以便页面更快准备好并变得可交互。
  2. 我们需要提高我们自己的 JS 和 React 代码的性能

我们引入的每一个变化都是经过广泛分析的结果。对现有大型产品进行性能优化通常需要数周的时间去分析数据,找出根本问题,而解决问题通常只需要几个小时。这个项目也不例外,我们同样经历了漫长的过程,在一次又一次的失败中前进,最终找到了改进INP的方法。

减少 React 水化

hydration 是 React 在客户端使静态 HTML 变得互动的过程。这是每个 SSR (服务器端渲染) 网站都会经历的一个步骤。在 hydration 之前,React 应用并不具备互动性。hydration 之后,它就变得完全互动了。那么中间的过程又是什么呢?

当用户与页面交互,且在 hydration 过程中,React 会记录并重播他们的交互。这对开发者来说非常方便,但这也带来了一定的成本:交互的 INP 比正常情况要差。接下来的图表说明了一个假设的 80 毫秒 INP 交互在 在 hydration 阶段发生时 变成了 235 毫秒的 INP 交互。

The two \(“hydration” and “interaction”\) steps, and the fact that a slow hydration impacts INP.

图展示了在hydration过程中,通常很快的互动是如何变得缓慢的。

以上是一个例子。手动测试显示,我们无法确定完整的hydration时长是否已添加到INP中,但有一些延迟被加入到标准的INP中。

最近最热门的 React 特性是服务器组件 (RSC)。得益于 RSC,你可以选择性地使页面的一部分在服务器上执行,而无需客户端渲染,类似于 PHP 的静态页面处理方式。Next.js 通过App Router 支持 RSC,而我们将之前工作的两个页面迁移到 RSC 是最初的尝试。

让我先说一个关键结论:通过查看我们的指标,我们发现补水不会成为主要的INP问题来源,因为它发生得非常快(平均120毫秒),我们预计大多数用户会在这个快速阶段之后进行交互。

At the time of writing, the INP for the Search page is 248 ms, and React hydration is 120 ms.

撰写本文之际,搜索页面的INP(交互式新建页面速度)是248毫秒,React hydration时间为120毫秒.

请留意,我们的应用采用了React 18,这个版本引入了一些hydration的改进。我们随后会在文章中进一步讨论这方面内容。

尽管如此,我们还是将首页迁移了到 Next.js App Router 以获得经验。最终,该项目最重要的目标之一是收集所有可能的收获,以确定未来其他页面的最佳迁移方法。

我们用来改进INP的所有数据

这些问题——“用户在网页上做了什么?他们与什么进行互动?”——对于确定要优化什么至关重要。要弄清楚这些问题,我们需要大量的数据。Preply 是一家极度重视数据的公司,我们一开始就拥有所有必要数据。若没有这些数据,要在一个季度内使 INP 进入“绿色区域”是不可能的。

为了提升INP的表现,我们采取了以下措施:

  • 我们将在每个会话期间记录所有Web Vitals(网络健诊指标)数据,并在DataDog上创建一个全局视图的仪表板来展示这些Web Vitals数据。

The generic DataDog dashboard we built on top of web-vitals library’s data.

我们在web-vitals的数据基础上构建了一个通用的DataDog仪表盘。

  • Next.js 的 自定义指标(尤其是 hydration 和 render 的时间)。
  • 所有提到的数据都可以在 SnowFlake 中获取并查询,因此 Preply 的任何人都可以分析这些数据并创建自定义仪表板。
  • 使用 Hotjar 来显示和分析用户行为的热图。
  • 使用标准的浏览器开发工具进行性能分析。使用 React Developer ToolsReact Scan 来捕捉不必要的重新渲染操作。

为了通知您,我们移除了DataDog的RUMSentry Web Vitals,因为它们与第1点提到的web-vitals库相比显得多余。尽管我们尝试了这些工具,但最终,当我们涉及到查询和聚合数据时,我们都在依赖我们自己的Snowflake实例,所有数据都经过Snowflake处理,之后我们将部分数据转发到DataDog,因此,保持所有工具的集中化并移除冗余显得非常自然。

一个关于web-vitals库跟踪数据的重要细节:我们最重要的仪表板之一显示了大量的(75%)<未识别>选择器。这使得这个仪表板变得没有意义。原因是一个已知的Google Chrome问题,这使得收集在用户操作后即刻消失的模态窗口中的DOM元素的选择器变得更加困难。web-vitals项目的作者们建议在这个GitHub评论中解决这个问题。我们利用了所有数据,即使没有解决选择器的问题,我们还是改进了INP。

The custom dashboard with the selectors of the INP offenders shows a very high number of unidentified elements.|

带有INP违规者筛选器的自定义仪表板显示出大量的未识别元素。|

我们是如何让INP变得更好的?

以下改进了搜索页面上INP的更改列表:

首页上改进了INP的改进措施列表:

并没有看到任何实质性的改进:

  • 利用 React 的 useDeferredValue
  • 优化设计系统的组件。
  • 清理搜索页面的代码,使其更简洁。
  • 快速优化 Preply Chat 的登录用户界面。
  • 停用 DataDog RUM。

最后一点,我们没做的是

  • 使用 Partytown 来卸载第三方脚本,以及尝试新的 React 编译器。

您可以在下面找到更多细节。

React 18 升级通知(INP 减少了 140 毫秒的输入延迟)

实际上,这并不是本文提到的2024年末页面速度项目的一部分,但当然值得一提。2024年初,所有产品团队在Preply的Devex团队的协调下共同努力,将React升级到v18版本。这次升级本身承诺带来了显著的水化和性能提升,即使不使用React Suspense,结果确实如此。在版本升级部署后的几天里,我们看到了更好的INP。

The INP of the Search page before the React 18 migration \(~460 ms\) dropped significantly immediately after the React 18 upgrade was released \(to ~323 ms\).

搜索页面在React 18迁移前的INP约为460毫秒,在React 18升级发布后立即显著下降至约323毫秒。

关于 React 18 新架构中 SSR 的 hydration,这篇文章提供了更详细的解释。

虚拟化长列表功能:INP减少40毫秒

在搜索页面上,最长的列表是导师出生的国家,列出了大约300个国籍。

The Country of Birth’s UI on Preply’s Search page.

Preply的搜索页面上的出生地用户界面

这听起来不是一个特别长的列表。在较慢的智能手机上,这300个React组件及其子组件添加到DOM中会花费相当长的时间(请注意,我们这里指的是React组件更新DOM的过程,具体是将所有新元素添加到DOM中,而不是指渲染步骤本身)。我们使用了React Virtuoso,因为这个库已经应用在我们的前端项目中,而所有类似的虚拟化库都相当类似。

FYI: 我们没有采用它,因为它目前还不被Preply.com支持的浏览器完全支持,但CSS content-visibility 具有巨大的潜力来利用CSS原生虚拟化。您可以在该文章中了解更多详情。提升渲染性能的更多内容可以在 “使用CSS content-visibility提升渲染性能” 这篇文章中找到。

消除键盘事件的抖动现象(输入延迟减少了20毫秒)

感谢我们通过web-vitals库收集的数据,我们发现键盘事件持续显示糟糕的INP,因此我们对这些事件进行了拆分。搜索页面上有三个输入框,在慢设备上输入内容非常困难。如下截图所示,通过去抖处理这些输入框后,INP明显改善。

Before: 632 ms INP while typing on the main learning subject’s input field, with most keyboard events resulting in a >300 ms INP. After, the same events result in a 72 ms INP.

之前:632 毫秒的 INP,在输入主学习主题时,大多数键盘事件导致 INP 超过 300 毫秒 (>300 毫秒)。之后,同样的事件导致的 INP 仅为 72 毫秒。

缓存重组件(响应时间减少30毫秒)

两个主要组件,即“Preply的工作方式”和“用户评论”组件,重新渲染花费了大量时间,增加了这些导致整个页面重新渲染交互的INP(输入延迟时间)。例如,当你关闭过滤器模态框并应用新过滤器时。你可以在接下来的React DevTools性能分析器截图中看到它们的影响。

The React DevTools’ profiler, in flamegraph view, shows the impact of the HowPreplyWorks and Reviews components.

React DevTools的性能分析工具,在火焰图模式中展示了HowPreplyWorks和Reviews组件的作用。

在这里提高INP非常直接:因为这两个组件是静态的,只需要使用React.memo进行缓存,这样一来,就能提高INP。

修复非欧盟状态管理隐私政策横幅(减少了15毫秒的INP)

问题再次是将全局 React 状态转换为局部的问题。每个新用户的第一次互动是与隐私横幅相关的。在主页和搜索页面上,非欧盟用户的隐私横幅在关闭时重新渲染整个页面。问题相当直接:用于决定是否显示横幅的 React 状态是在页面级别存储的,位于 React 组件树的较高层级。只需添加一个仅处理隐私横幅逻辑(保存偏好到本地存储并隐藏横幅)的中间组件,即可改善 INP。

避免“Tooltip”重新加载整个页面,减少 10 毫秒的 INP

我们注意到一些奇怪的现象:第一次与搜索页面互动(而不是首页)时速度很慢。无论你与页面上的什么元素进行互动——第一次互动总是很慢,但后续的互动速度会快一些。真正的顿悟时刻是当我们意识到即使是触碰非互动元素(比如页面的背景),输入延迟(INP)依然很差。

我们是怎么做的:

  1. 利用浏览器的性能工具,我们记录了一次非常明确地展示了问题的交互过程。
  2. 记录显示问题是由于 touchstart 事件引发的。
  3. 我们逐一移除了主 DOM 元素(如htmlbody<div id="__next">)上的所有 touchstart 事件处理程序。

The browser dev tools visualize the event handlers, allow you to remove them, and jump to the listening JS module. Initially, there were more than 30 listeners.

浏览器的开发者工具可以显示事件处理程序,可以让你移除它们,并可以跳转到对应的JS模块。最初,监听器的数量超过了30个。

  1. 所有处理程序都对缓慢的 INP 负有部分责任,但其中一个导致了整个页面的重新渲染。
  2. 在事件监听器标签中,浏览器开发工具最初指向了我们 Sentry 的监听器(顺便提一下,这些监听器也可以用于测量 Web Vitals)。
  3. 禁用 Sentry 后,问题仍然存在,事件监听器标签将我们指向了我们自行构建的基于 Radix UI 的 Tooltip 的工具提示。

原因在于基础的 TypeScript 失误:

  1. 初始的 tooltip 状态为 const [open, setOpen] = useState(props?.open),这意味着 open 是一个 boolean 或者 undefined 类型的值。
  2. 当点击页面上的任意位置时,onClickOutside 处理程序会执行 setOpen(false)。因此,openundefined 变为 false,导致子组件重新渲染。
  3. 我们通过将初始状态设置为 const [open, setOpen] = useState(props?.open ?? false) 来解决了这个问题,这样就避免了 undefined 作为可能的状态。

通常来说,我总是建议“让 TypeScript 更好地帮助你”,通过减少可能的类型:使用 联合类型 而不是泛型,使用 区分联合 而不是可选属性(当可能时),避免将假值与布尔值混在一起等。你可以在我的 “我是如何让读我代码的下一位开发者更轻松的” 这篇文章中了解更多关于这个主题的内容。

为 Usercentrics 更新以适应欧盟隐私政策横幅(搜索页面的 INP (输入延迟) 分别缩短了 5 毫秒,而首页缩短了 40 毫秒)

对于欧盟用户,我们使用Usercentrics(https://usercentrics.com/)。具体来说,我们使用的是V2版本的Usercentrics。与前一点类似,从INP的视角看,隐私横幅还算可以,除非你在没有接受或更改隐私设置的情况下直接关闭它。关闭横幅时会执行大量我们无法控制的JavaScript代码,这影响了许多Preply用户

Usercentrics团队建议我们将迁移至他们的V3版本,这样可以解决这个问题(影响自然排名的问题,即INP)。但我们需要将GTM(Google Tag Manager)版本更新到最新,以加载Usercentrics横幅。我们与负责GTM的同事合作,帮助他们完成迁移工作,解决了另一个影响Preply.com所有页面的INP问题的来源。

值得注意的是,更新Usercentrics对首页产生了重大影响,其中隐私横幅是为数不多的互动元素之一。不过,对高度互动的搜索页的影响却很小。

再次优化我们之前优化过的东西(INP减少了15毫秒)

这些改进消除了最严重的INP。然后,我们有几周时间(请参见图表)没有明显进步。我们已经接近了80/20帕累托法则的极限,而接下来的所有改进措施将带来更少的效益,同时需要更多的时间来实施(但我们已经没有多余的时间,项目计划在2024年底前完成)。

The INP graph shows that after many quick wins, we had no improvements for a few weeks.

INP图表明,虽然我们曾经取得了一系列快速胜利,但接下来的几周里,我们并没有看到任何进步。

我们回到已经优化的问题上,进一步优化它们。最终,这些被证明是低垂的果实(即容易实现的目标),因为它们影响了核心用户流程,为什么不进一步优化这些核心流程呢?因此,我们开始使用20倍的CPU减速来测试性能改进,这肯定更接近我们的目标设备,相比之下,即使是减慢6倍的高端MacBook Pro,仍然比大多数市场上的设备快,特别是在提到移动设备时。

它成功了,我们可以更进一步地削减INP并与项目的OKR对齐 🎉。

更新消息:Chrome DevTools 134 包含经过校准的节流配置文件 _,可以更准确地模拟低端或中端设备等。

将主页迁移到应用程序路由器(INP减少了10毫秒)

next.js App Router 和 RSC(React 服务器组件)仅略微提高了 INP 的性能。我们期望更多,但这是我们的失误:在我们最初使用 App Router 进行的 POC 中,我们错误地将 TBT(完全阻塞时间) 作为 INP 的代理指标,因此我们的期望是不切实际的。

但是还有更多的事情要告诉你们!仅仅说“App Router 只是稍微改进了一下”显然低估了它的潜力。为什么呢?我之前告诉过你们,我们只是迁移了主页,并没有重新编写它!

所以我们建立了一个使用全新 Next.js 应用程序的 PoC(概念验证)。我们只选择了支持 RSC 的库(例如国际化),并对部分页面进行了重构,考虑到了数据缓存的需求。结果(性能测试是在本地生产模式下,使用 3G 网络和模拟 20 倍 CPU 负载进行的)非常

这些结果证明了App Router是公正的!然后,我们一致认为,最优且长期的解决方案(在项目的整个生命周期内不可实现)是从一个全新的Next.js项目开始重写在多年快速发展中添加到Next.js的所有功能。

useTransition(useTransition), 等等, 如等待用户交互响应。

在项目期间,我们努力深入探究,找出问题的根本原因并解决。我们不想把问题藏起来,让事情变得更棘手。

尽管如此,由于缺乏合适的设计,这些问题在项目周期内无法解决,而“欺骗”浏览器是加快某些操作的唯一方法。这里“欺骗”的含义是:

在一篇详细的揭秘 INP:新工具和实用见解 文章中,Vercel(Next.js 的创造者)分享了 await-interaction-response 这个包。该包的源代码如下:

    /**

* 返回一个在下一帧解析的 Promise。
     */
    export default function interactionResponse(): Promise<unknown> {
      return new Promise((resolve) => {
        setTimeout(resolve, 100); // 以防动画帧从未触发时的回退方案。
        requestAnimationFrame(() => {
          setTimeout(resolve, 0);
        });
      });
    }

本质上,这是一个小技巧,用来避免阻塞浏览器主线程并推迟执行你的重负载代码。这当然可以改善INP性能,但在我们的案例中反而让问题更糟,因为它像是在说“别担心,缺乏设计和开发中的反模式没关系,只需使用这个解决办法”,这正是我们不想传播的信息。

React的useTransitionAPI更为优雅,因为它直接内置于框架中,但在我们的情况中,使用它反而掩盖了根本问题,而不是帮助解决或教导如何避免这些问题,而是帮助理解和解决这些问题,同时消除现有的性能瓶颈。

但那些想找短期和快速解决方案的人……嗯,还是得记住他们哦 😅。

仅有一点提示: 如果您正考虑实现自定义生成器,请不要使用 requestIdleCallback! 在我们开发设计系统视觉覆盖率的过程中,我们注意到由于其他密集型任务,浏览器经常在几秒钟后才调用回调函数。在Preply设计系统视觉覆盖率实现细节这篇文章详细介绍了我们所做的所有性能优化。

React 的 useDeferredValue 的用法(不涉及 INP 的改进)

我们对此感到有点意外。React 的 useDeferredValue 在用户输入的内容(在这种情况下是我们要学习的语言列表)需要较长时间更新到页面时,可保持输入字段的响应速度。重构一个输入字段后,与防抖处理输入字段的值相比,没有发现任何改善。这又是为什么呢?

我们注意到,当需要渲染的项目在React渲染阶段(即React执行组件函数返回JSX时)很重,但在DOM协调阶段(即React添加、更新或移除DOM元素时)却很轻。我们的情况则相反,组件在渲染上足够快,但生成的DOM元素却非常多(你可以阅读X上的一篇讨论以了解更多细节),这使得useDeferredValue的好处几乎不存在了。

设计系统组件优化(不涉及 INP 改进)

Path(Preply的设计系统)被广泛运用:搜索页面有875次使用了Path组件,76%的用户看到的内容都来自Path;你可以通过这篇文章《为什么以及Preply如何衡量设计系统的影响》了解更多统计信息的收集方法:Visual coverage: Why and How Preply Measures the Impact of the Design System。搜索页面的渲染树中有一个特别繁重的部分表明,使用最频繁的两个Path组件(LayoutFlex和Text),在将React属性转换为CSS类名的过程中存在改进空间,这影响了整个页面的INP值。

重构路径组件的过程不会一夜之间完成,我们花了几天时间对 LayoutFlex 组件进行高强度的测试与重构,以避免整个网站出现任何回退。所有这些繁重的工作为设计团队安全地进行组件测试和重构打下了坚实的基础,但就 INP 而言,并没有看到任何改进。结果证明我们的分析有误。

整理搜索页面的代码(不含 INP 改进)

近年来,产品团队启动的数百次实验仍然存在于代码库中。有些是废弃的代码,有些只有在特定的 A/B 测试条件下才会动态加载,即使实验结束也未被移除。有些始终被导入,导致 JS 包变大。

我们移除了搜索页面代码库中的15%(约7000行代码),持续了两周,但这并没有改善搜索页面的INP。这在整个项目中反复出现(稍后我们会谈到Next.js App Router),但减少发送的JavaScript代码从未改善我们搜索页面的INP。需要注意的是,这里的讨论仅限于INP,减少JavaScript代码量总是有好处的。

快速优化 Preply Chat,让已登录用户用起来更顺手(无需对 INP 进行改进)

已登录的用户可以通过页眉中的 Preply 聊天按钮,在同一页面内打开聊天窗口。我们从 Hotjar 发现,很多用户经常打开 Preply 聊天。

A screenshot of the Search page shows the Chat button at the top for logged-in users.

这张搜索页面的截图显示,顶部有一个聊天按钮,专门给已登录用户使用。

真没想到,考虑到索引页面和大量SEM活动会吸引大量新用户到搜索页面,但其中大部分尚未登录,但从快速查看了一下后,我们发现搜索页面上的浏览量有80%是来自已登录的用户 🤯。由于Preply聊天相对比较复杂,因此我们采用了mentioned await-interaction-response的方式,延迟了一些Preply聊天功能的执行。我们并未见到预期中的INP改进,这意味着我们之前的假设再次被证明是错误的。

取消 DataDog RUM(没有交互性能改进)

经过广泛的本地测试,尽管看起来很奇怪,DataDog RUM(DataDog RUM)似乎导致了更严重的INP。幸运的是,对我们来说,这个工具是多余的(因为我们主要依赖web-vitals这个库),于是我们决定移除它。然而,移除之后,我们并没有发现任何改善。

使用 Partytown 卸载第三方脚本的做法(我们决定放弃)

我们加载了许多第三方脚本,其中一些是由开发人员控制加载的,而大约有~40个是通过GTM加载的,且不受开发人员控制。虽然我们知道通过GTM加载的脚本会对页面产生负面影响,但我们放弃了尝试将其移至Web Workers中处理。下面来解释一下原因。

  1. 一旦通过GTM加载,某些脚本会在DOM中追加更多的脚本,这些脚本在主线程中执行,削弱了使用Partytown的好处,部分上。
  2. 多年通过GTM添加的脚本和可能在其上构建的框架或集成,几乎可以肯定地破坏了一些功能或行为,而破坏的原因和错误结果之间没有明确的关联。

由于我们所有人都依赖数据,而且项目时间很紧,考虑到这项工作的投资回报不明,我们决定放弃这个项目。

我们甚至都没试过的新 React 编译器工具(我们直接跳过了)

目前,在撰写本文时,React 编译仍在建设中。然而,我们与 Devex 团队讨论的限制是 Next.js 从 v14 升级到 v15 以及 React 从 v18 升级到 v19,这些升级耗时较长,超出了我们的项目时间范围。Wakelet 分享了早期反馈关于他们在采用新编译器后对网站性能指标的改进。

这些努力是否也改善了用户体验?

答案是:是的!(YES!) 在使用6倍和20倍CPU减速的情况下,用户体验的改进显而易见,但仍有许多改进余地。从这个角度来看,输入延迟(INP)证明是一个很好的指标;它真正地作为一个试金石,用来衡量在没有顶级设备时,使用产品的难度。虽然所有的Web Vitals(网络关键指标)都很有价值,但INP独特地测量了用户在整个会话期间的整体体验,无论用户的浏览时间是短暂的还是长久的。

其他

这篇文章省略了很多项目细节,因为这些细节对读者来说并不关键或相关。我来简单说说几点事实和建议,

  1. 我们在一个季度的时间里工作了一个多月后,看到了第一个INP改进。
  2. 周末对于衡量我们工作的效果非常关键,因为我们发现仪表板需要24-48小时才能反映出INP的变化
  3. 由于其他产品团队也有一个重要的产品目标,我们无法阻止他们在这几页上运行实验。这并不是最理想的情况,但由此产生的摩擦并不大。
  4. Devex团队辛勤工作将Next.js从13升级到14,并利用更快的Turbopack来进行本地开发。
  5. 项目最初的目标是优化INP和TTFB这两个指标。后来,这两个指标被拆分成两个独立的项目。
  6. 为了使用App Router,我们不得不将所有的LESS模块转换成SCSS(也包括在设计系统中)。

一定要在多台电脑上验证你的假设:这种情况不止发生过一次,我们中有人发现了可能的改进点,但在其他笔记本电脑上却看不到同样的效果(可能是由于后台僵尸程序,用户被纳入数据采样导致网站变慢等)。

中期和长期计划

所有的这些改进都是短期的,如果我们不将性能作为我们在开发产品时的首要考虑,这些好处可能会很快消失。我们还没有正式化所有为这个目标所需的所有活动,但我们有一些想法和计划。

  1. (通过这篇文章你已经看到了它的实际应用)监控 Web Vitals 以发现退化问题。
  2. (已经完成)将 Web Vitals 添加到我们实验框架的仪表板和所有关心的产品指标中。
  3. 在 PR 模板中加入性能数据。
  4. (已经在进行中)运行研讨会分享收获并传播 React 最佳实践给所有前端开发者。
  5. 运行一些研讨会分享如何从性能角度处理现有产品的重构工作。
  6. 讨论 App Router 在我们产品及其相关基础设施中的作用。
要点如下

✅追踪大量RUM(真实用户监控)数据并随时都能掌握它非常重要。

从一开始就采取100%数据驱动的方法至关重要。如上所述的优化并不复杂,但但在动手写代码之前识别这些问题很重要。

✅ 不要盲目地跟随别人的做法和分享(包括这篇文章);不要想当然地认为更流行的框架就能解决你的问题。通过这些努力,最终我们通过优化现有的代码实现了我们的INP目标。

额外资源
参与这个页面速度项目的大神们。

我想感谢所有参与的朋友们,谢谢大家的帮忙,真的 🤗

  • Maksym Ridush,感谢他进行的初步深入分析,这促成了页面速度项目的启动 👏。

来自负责搜索页面的团队:

  • Artem Yermak,感谢你不断的支持和改进了INP 💪。
  • Ivan Biletskyi,感谢你出色的反馈和知识分享,真的非常感激 ❤️。

来自,负责首页的团队

Preply设计系统的工程师已经被借调到页面加载速度优化项目:

Vadym Vlasenko,总能深入细节,并挑战我们。

来自不同团队的每个人帮了我们一把

  • 感谢 Mate Papp 在 DevEx 方面的所有帮助,特别是帮助我们完成了 Next.js v14 的迁移。
  • 感谢 SRE(系统可靠性工程)团队的 Kyryl Sablin,感谢您一直的支持和帮助。

当然,要感谢那些帮助让这篇文章更好的审稿人 🤗

从改善我们的工程文化到成为一家AI原生的公司……你有兴趣加入我们,在这里,工作、成长和学习是同步进行的吗?Preply 正在快速发展壮大,我们正在积极寻找有才华的候选人加入我们的工程团队!如果你对迎接新的挑战感兴趣,在这里查看我们的空缺职位

點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺(jué)得本文不錯(cuò),就分享一下吧!

評(píng)論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評(píng)論
  • 收藏
  • 共同學(xué)習(xí),寫(xiě)下你的評(píng)論
感謝您的支持,我會(huì)繼續(xù)努力的~
掃碼打賞,你說(shuō)多少就多少
贊賞金額會(huì)直接到老師賬戶(hù)
支付方式
打開(kāi)微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊(cè)有機(jī)會(huì)得

100積分直接送

付費(fèi)專(zhuān)欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會(huì)
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢(xún)優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)

舉報(bào)

0/150
提交
取消