浏览器之性能指标-FID

如果坚持做一件事就要把目标放低一点,确保自己可以实现,不要把目标定的很高,让人高不可攀,无法坚持

大家好,我是柒八九

前言

今天我们来聊聊另外一个比较重要的性能指标FID

如果想了解该系列文章(浏览器底层原理&优化方案),可以参考我们已经发布的文章。如下是往期文章。

  1. 页面是如何生成的(宏观角度)
  2. Chromium 最新渲染引擎--RenderingNG
  3. RenderingNG中关键数据结构及其角色
  4. 浏览器之客户端存储
  5. 浏览器_知识点精讲
  6. 像素是怎样练成的
  7. 浏览器之资源获取优先级(fetchpriority)
  8. 浏览器之性能指标_FCP
  9. 浏览器之性能指标-LCP
  10. 浏览器之性能指标-CLS

你能所学到的知识点

  1. 前置知识点
  2. FID是个啥
  3. 为什么会出现输入延迟呢
  4. FID VS TTI
  5. FID 有助于SEO
  6. FID 得分
  7. 优化FID得分
  8. 测量FID
  9. 最大潜在首次输入延迟
  10. 能否在Lighthouse测量 FID ?

好了,天不早了,干点正事哇。


1. 前置知识点

前置知识点 ,只是做一个概念的介绍,不会做深度的解释。因为,这些概念在下面文章中会有出现,为了让行文更加的顺畅,所以将本该在文内的概念解释放到前面来。如果大家对这些概念熟悉,可以直接忽略

用户输入事件

当用户在浏览器中与网页进行交互时,会触发许多用户输入事件,这些事件会触发浏览器的渲染过程。

鼠标事件 (Mouse Events)

事件名称 描述
click 用户在页面上单击鼠标按钮时触发,通常用于响应单击动作。
dblclick 用户在页面上双击鼠标按钮时触发,通常用于响应双击动作。
mousedown 用户按下鼠标按钮时触发,通常用于捕捉鼠标按下的瞬间。
mouseup 用户释放鼠标按钮时触发,通常用于捕捉鼠标释放的瞬间。
mousemove 用户在页面上移动鼠标时触发,通常用于跟踪鼠标位置变化。
mouseover 用户将鼠标移动到页面元素上时触发,通常用于实现悬停效果。
mouseout 用户将鼠标移出页面元素时触发,通常用于实现悬停效果的结束。

键盘事件 (Keyboard Events)

事件名称 描述
keydown 用户按下键盘上的键时触发,通常用于捕捉键盘按下的瞬间。
keyup 用户释放键盘上的键时触发,通常用于捕捉键盘释放的瞬间。
keypress 用户按下并释放键盘上的键时触发,通常用于处理字符输入。

表单元素事件 (Form Element Events)

事件名称 描述
focus 当页面元素获得焦点时触发,通常用于处理用户在表单元素上输入内容的开始。
blur 当页面元素失去焦点时触发,通常用于处理用户离开表单元素后的操作。
change 当表单元素的值改变时触发,通常用于处理输入内容变化的情况。
submit 当表单提交时触发,通常用于处理表单数据的提交。

触摸事件 (Touch Events)

仅适用于支持触摸屏的设备

事件名称 描述
touchstart 用户触摸屏幕时触发,通常用于捕捉触摸操作的瞬间。
touchmove 用户在屏幕上滑动时触发,通常用于跟踪触摸滑动的位置变化。
touchend 用户停止触摸屏幕时触发,通常用于捕捉触摸操作的结束。

这些用户输入事件可以通过JavaScript绑定到特定的页面元素上,然后在事件触发时执行相应的操作。浏览器会根据这些事件的触发,执行相应的渲染和交互操作,以实现用户与网页的交互体验。


TTI

TTI:是Time to Interactive的简写,中文名称可交互时间

它用于衡量网页加载完成后,用户可以与页面进行交互的时间。它是页面加载过程中的一个关键度量标准,更准确地反映了用户实际体验的时间点。

TTI指标包含两个要素:

  1. 加载完成时间 (Load Event End):指浏览器完成文档加载的时间点。也就是整个网页及其所有资源(如CSS、JavaScript、图像等)都已下载完成,但不一定是所有资源都已经执行完毕

  2. 主线程空闲时间 (Main Thread Idle Time):指主线程空闲并且可以响应用户输入的时间点。这意味着网页的JavaScript执行已经完成,没有长时间的阻塞操作,并且页面可以对用户的交互事件作出快速响应

TTI可以视为用户可以与网页完全交互的时间点,而不会感到页面过于卡顿或响应缓慢。更短的TTI意味着用户能够更快地开始浏览、点击按钮或输入内容,提高用户体验和页面的互动性。


SEO

SEO(Search Engine Optimization,搜索引擎优化)是一种通过优化网站和其内容,以提高网站在搜索引擎中的排名和曝光度的策略和技术。

目标是使网站在用户搜索相关关键词时,能够在搜索引擎结果页面中获得更好的展示位置,从而吸引更多的有针对性的访问流量。

SEO的主要目的是让搜索引擎更好地理解网站内容,并认为网站提供的信息对用户有价值,进而将其排名靠前。通过遵循搜索引擎的规则和准则,提供高质量的内容和良好的用户体验,可以提高网站在搜索结果中的可见性和排名。


navigator.sendBeacon 是一个用于在浏览器中发送异步请求的 API。它的作用是在页面卸载前(例如用户离开当前页面或关闭页面)尽可能可靠地发送数据,以确保在这种情况下也能成功发送数据。

与常见的 Ajax 请求(例如使用 XMLHttpRequestfetch)不同,navigator.sendBeacon 的主要优势是它不会阻止页面卸载 。当浏览器正在关闭或导航到另一个页面时,常规的异步请求可能不会完成,因为浏览器会在这些请求完成之前中止连接。但是,navigator.sendBeacon 通过将数据放入浏览器的发送队列,允许在页面卸载时继续异步发送数据。

这使得 navigator.sendBeacon 特别适合在用户离开页面时需要进行后台数据记录或分析的情况。通常在发送分析数据或日志数据等不需要立即得到响应的情况下使用。

使用 navigator.sendBeacon 时要注意以下几点:

  • 由于 navigator.sendBeacon 是异步执行的,它不会等待服务器的响应,因此无法得知请求是否成功。因此,它主要用于日志记录和数据追踪等情况,不适合需要服务器响应的场景。
  • 发送的数据必须是 BlobBufferSourceFormData 或者字符串类型的数据。
  • 由于 navigator.sendBeacon 发送的是 POST 请求,因此服务器端应该能够处理 POST 请求,并相应地解析数据。

我们通过一个简单的示例来介绍一下它的用法:

javascript 复制代码
const data = {
  event: 'button_click',
  timestamp: new Date().toISOString(),
  user_id: '前端789',
};

const body = JSON.stringify(data);

if (navigator.sendBeacon) {
  // 使用 sendBeacon 发送数据
  const isDataSent = navigator.sendBeacon('/log', body);

  if (isDataSent) {
    console.log('数据已成功发送。');
  } else {
    console.log('数据发送失败。');
  }
} else {
  // 如果浏览器不支持 sendBeacon,则使用 fetch 作为备选方案
  fetch('/log', { method: 'POST', body })
    .then(() => console.log('数据已成功发送。'))
    .catch((error) => console.error('数据发送失败:', error));
}

上面的内容,算是这篇文章的开胃菜,而下面的内容,是我们今天才是我们今天的四菜一汤

2. FID 是个啥

FID:是First Input Delay的简写,中文名称首次输入延迟。是核心 Web 指标之一,用于衡量网页交互性的网络性能指标

它是一个真实用户网页性能指标 ,用于追踪用户在进入网页后首次与网页进行交互的时间,直到浏览器开始处理该交互(即浏览器的主线程空闲时)。

这两个事件之间的时间称为Input Delay(也称为Input Latency) - 中文翻译为: 输入延迟

换句话说,FID反映了用户交互(例如点击或触摸链接或按钮)和浏览器响应我们的操作并开始处理它之间的延迟时间

想象一下,当我们访问京东或者淘宝并期望某个元素立即打开时,但是我们点击的超链接却对我们的请求无动于衷 。从技术上讲,这是因为浏览器的主线程正在处理其他请求 ,它此时也分身乏术

FID所测量的用户输入事件必须是离散的(有限的)。

连续类型的用户交互,如缩放或滚动页面,无法准确地使用该指标进行测量。这是因为它们通常不在浏览器的主线程上运行并具有不同的约束条件。

这点可以参考我们之前聊过的关于像素是怎样练成的图层提升(Layer Promotion)的部分

下面的图,很好的解释了,当用户首次加载后,在点击元素时,出现无法及时响应用户事件的原因。


FID仅测量第一个用户交互

FID可以说是我们网站的脸面。用户首次与我们的页面进行交互对于他们对网页性能的体验和感知至关重要。

此外,大多数阻塞浏览器主线程的情况发生在网页生命周期的最初时刻,也就是加载关键资源 的时候。FID是一个帮助我们解决这个问题的指标,确保加载这些关键资源不会使我们的网站感觉笨重和反应迟钝。


FID测量的是输入延迟,而不是处理延迟

FID不测量由于用户交互而导致的网页实际处理或更新。这是因为开发人员可以通过将事件处理程序与与事件相关的任务分离来操纵FID。


3. 为什么会出现输入延迟呢

输入延迟(Input Delay)是指在没有用户请求的情况下加载页面元素,例如图像或脚本。

当用户访问一个网页时,浏览器会加载页面中包含的各种资源,如图像、脚本、样式表等。通常情况下,这些资源是根据页面的内容和结构进行请求和加载的。

然而,在某些情况下,这些资源可能会在没有用户直接请求的情况下被加载。例如,当网页中的脚本文件被设置为自动加载,并且不是在用户直接与网页交互时才加载,就会导致输入延迟。这意味着用户在浏览网页时,可能会遇到加载资源导致的页面反应迟钝或交互体验受阻的情况。

根据谷歌的说法,导致长时间输入延迟的原因之一是JavaScript执行。特别是对于需要在运行任何事件监听器之前由浏览器执行的大型JavaScript文件。

为什么会这样呢?因为正在加载的JavaScript代码可以改变浏览器的后续操作。

当浏览器等待确定下一步操作时,它会导致网站反应迟钝,从而增加输入延迟。这就像浏览器被困在一个交通拥堵中,通过最小化JavaScript文件可以提高流畅性。这样可以减少浏览器注册事件所需的时间。


4. FID VS TTI

TTI衡量的是页面完全可交互 所需的时间,而FID则追踪页面完全可交互之前的用户输入。

当页面上已经呈现了有价值的内容(通过FCP进行测量),大多数页面元素都已注册事件处理程序 ,并且用户交互在50毫秒内得到处理时,就会注册TTI

TTILighthouse中显示。

与此同时,FID可以追踪例如当用户点击一个链接时,该链接出现在大多数页面元素的事件处理程序注册之前。与TTI不同,FID允许我们捕捉到那些早期的、关键的交互


5. FID 有助于SEO

  1. FID是最令人兴奋的网络性能指标之一,因为它是一个纯粹的真实用户指标 。它无法在实验室测试中进行模拟,因为它需要实际用户的输入才能进行测量FID关乎真实用户在进入我们的页面时的体验。

  2. 作为一个真实用户指标,监测和优化FID非常重要,因为它定义了我们网站的用户体验。

  3. FID现在是谷歌的官方排名因素之一。

    • FID是追踪网站响应性
    • CLS追踪视觉稳定性
    • LCP追踪加载速度

当谷歌于2021年6月开始使用核心网页要素作为排名算法的一部分时,FID成为了其中之一。


6. FID 得分

研究表明,100毫秒 的延迟被认为是由相关源(Associated Source)引起的。0.1秒是用户感觉系统反应即时的极限时间。

相关源(Associated Source),在网络性能和Web Vitals度量中,是指与用户输入延迟(Input Delay)或其他性能指标相关的资源任务

基于这些原因,最好尽量将我们的FID控制在100毫秒以下。

以下是谷歌在PageSpeed Insights中为FID设定的阈值:

  • FID在100毫秒或以下被认为是良好的;
  • FID在100-300毫秒之间需要改进;
  • FID超过300毫秒被认为是较差的。

根据这些阈值,我们可以评估并改进我们的网页在FID方面的表现。

浏览器仍然需要运行与用户输入相关的任务,而FID并不测量这部分时间。因此,在某些情况下,我们的FID可能在100毫秒以下,但页面仍然可能会感觉有些反应迟钝。


7. 优化FID得分

如果我们对FID的得分不满意,通常意味着我们需要改进JavaScript或CSS的使用方式。

以下是我们可以进行FID优化的步骤:

优化CSS代码

对于CSS文件,它们需要尽快下载和解析,以便浏览器可以渲染页面的布局。由于这个原因,我们在减少CSS对FID的影响方面的选择是有限的。然而,我们可以参考CSS最佳实践,例如对文件进行压缩和缩小,或删除未使用的CSS代码。

这里多说一句,其实针对CSS优化也有很多的点,我打算单开一个关于CSS优化的文章,所以在这里就不在展开说明了。

优化JavaScript代码

当存在长时间输入延迟时,通常是JavaScript任务造成的。长时间阻塞浏览器的主线程,导致它无法处理用户输入。

以下是我们可以使用的一些策略,以减少JavaScript执行对主线程阻塞的时间:

创建小的异步任务

长时间的任务会阻塞主线程,不允许其处理用户输入。如果将它们分解为较小的任务,用户输入可以在它们之间被处理。尽量保持任务在50毫秒以下以确保安全。

我们使用setTimeout模拟长任务。

javascript 复制代码
function performTaskPart1() {
  console.log("Part 1");
}

function performTaskPart2() {
  console.log("Part 2");
}

function performTask() {
  // 将长任务分成多个小任务。
  performTaskPart1();
  setTimeout(performTaskPart2, 0);
}

performTask();

生成服务器端内容

尽量减少需要在客户端进行后处理的数据量。这样可以减少浏览器渲染页面时需要执行的工作量。

这点尤其针对SPA项目,大部分都采用的CSR(Client Side Rendering)

页面托管服务器只需要对页面的访问请求响应 一个如下的空页面

html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <!-- metas -->
    <title></title>
    <link rel="shortcut icon" href="xxx.png" />
    <link rel="stylesheet" href="xxx.css" />
  </head>
  <body>
    <div id="root"><!-- page content --></div>
    <script src="xxx/filterXss.min.js"></script>
    <script src="xxx/x.chunk.js"></script>
    <script src="xxx/main.chunk.js"></script>
  </body>
</html>

页面中留出一个用于填充渲染内容的视图节点 (div#root),并插入指向项目编译压缩后

  • JS Bundle 文件的 script 节点
  • 指向 CSS 文件的 link.stylesheet 节点等。

浏览器接收到这样的文档响应之后,会根据文档内的链接加载脚本与样式资源,并完成以下几方面主要工作:

  1. 执行脚本
  2. 进行网络访问以获取在线数据
  3. 使用 DOM API 更新页面结构
  4. 绑定交互事件
  5. 注入样式

其中,执行脚本 就需要安装每个前端框架的内置方法,将JS代码生成对应的Virtual DOM,然后在通过浏览器内置API将其转换为DOM, 然后才会进行事件的绑定,这就大大影响了FID

所以,在CSR项目中存在很大的FID,可以尝试用SSR(Service Side Rendering)。(当然,也可以选择类似Svelte的编译型前端框架,但是这不在本文的讨论范围内)

下面是用ExpressNode端生成页面内容。

javascript 复制代码
const express = require("express");
const app = express();

app.get("/", (req, res) => {
  // 服务端内容生成
  const serverContent = "Hello, 柒八九!";
  res.send(serverContent);
});

app.listen(3000, () => {
  console.log("Server started on port 3000");
});

其实,还有很多的渲染方式,可以参考之前的文章 XXR部分。


按需加载第三方代码

第三方代码,如分析工具(sentry)或者嵌入式地图(像Google地图百度地图),通常会阻塞主线程。虽然有时分析代码需要在开始时加载以确保整个访问过程正确跟踪,但我们可能会发现页面上的某些第三方代码不需要立即运行。首先优先加载我们认为对用户提供最大价值的内容。

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <title>前端柒八九</title>
</head>
<body>
  <!-- 重要 script 优先加载 -->
  <script src="essential.js" defer></script>

  <!-- 非必要 script 可以延后加载 -->
  <script src="non_essential.js" defer></script>
</body>
</html>

当然,我们还可以利用import()React-Router/React中实现业务层面的按需加载。


使用Web Worker

我们可以将一些主线程工作委托给Web Worker,以减轻主线程的工作负担。Web Worker允许将一些JavaScript代码委托给工作线程运行,这意味着主线程的工作较少,输入延迟较少。

用一个简单的demo来说明一下

main.js

javascript 复制代码
const worker = new Worker("worker.js");

// 向work发送消息
worker.postMessage("Hello from the main thread!");

// 接受来自work的消息
worker.onmessage = (event) => {
  console.log("Message from worker:", event.data);
};

worker.js

下面这段代码,运行在Web Worker线程中。和主线程分离,所以不会阻塞主线程。

javascript 复制代码
self.onmessage = (event) => {
  const messageFromMain = event.data;
  console.log("Message from main thread:", messageFromMain);

  // 执行耗时任务
  const result = doSomeWork();
  
  //将执行结果发送到主线程
  self.postMessage(result);
};

function doSomeWork() {
  // 模拟耗时任务
  return "耗时任务";
}

如果想了解更多关于Web Worker,可以参考我们之前写的Worker线程


推迟未使用的JavaScript代码

使用asyncdefer,以便仅在需要时执行JavaScript代码。如果我们使用的是高版本JavaScript,可以配置ES6模块以按需加载。

这是一个老生常谈的方式,这里就不展开说明了。

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <title>前端柒八九</title>
</head>
<body>
  <!-- 推迟到DOM被渲染完成,再执行加载该脚本 -->
  <script src="script.js" defer></script>
</body>
</html>

减少未使用的Polyfill

Polyfill是在用户使用较旧的浏览器时所需的。开发人员使用它们来使用现代JavaScript构建网站,并仍然向不支持某些现代功能的浏览器提供所有功能。

确保在不需要时不运行Polyfill。使用module/nomodule交付独立的包。

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <title>前端柒八九</title>
</head>
<body>
  <!-- 为现代浏览器加载支持 ES 模块的现代 JavaScript。 -->
  <script type="module" src="modern.js"></script>

  <!-- 为不支持 ES 模块的旧版浏览器加载传统 JavaScript。 -->
  <script nomodule src="legacy.js"></script>
</body>
</html>

当然,我们现在项目大部分是基于Webpack/Vite等前端工具开发,我们可以在处理的时候,都是利用Bable进行代码转义处理,在Bable中是可以配置相关的配置,来处理针对不同浏览器和特性的polyfill打包问题。


闲时直至紧急

闲时直至紧急(Idle until urgent)是由谷歌提出的一种代码评估策略

这种策略结合了两种最流行的代码评估方法------急切评估(eager evaluation)和惰性评估(lazy evaluation)。

  • 急切评估(eager evaluation)意味着我们的所有代码都会立即运行。这种方法会导致页面加载时间较长,直到完全可交互,但之后运行顺畅,没有任何中断。

  • 惰性评估(lazy evaluation)则是相反的方法------只有在需要时才运行代码。虽然它有其优点,并且对某些网站可能很有用,但惰性评估意味着一旦需要运行代码,我们就会面临输入延迟的风险。

  • 闲时直至紧急(Idle until urgent)将这两种方法的优点结合起来,以提供一种聪明的代码评估方式,从而使输入延迟最小化。

闲时直至紧急(Idle until urgent)允许我们在空闲时段运行代码,充分利用主线程。同时,它保证了紧急需要的代码立即运行。

采用闲时直至紧急的方法是改进首次输入延迟的好方法。由于代码执行仅在空闲时段进行,可以最小化主线程的阻塞时间。


优化输入延迟

当浏览器在用户与网站进行交互时(如点击按钮或链接)响应时间过长时,长时间的输入延迟就会成为一个问题。为了解决这个问题,我们可以使用HTML属性来控制脚本的下载(重新排序脚本文件和优化代码中的图像)或删除不必要的脚本。

以下是一些可采取的措施来减少长时间输入延迟的问题:

  1. 重新排序脚本:通过将关键脚本放在页面的顶部,使其尽早下载并尽快执行。这样可以确保与用户交互相关的脚本能够快速加载和运行。

  2. 优化图像:通过使用适当的图像格式(如WebP)和压缩图像文件大小,减少图像的加载时间。优化图像可以提高页面的加载速度,减少输入延迟。

  3. 删除不必要的脚本:检查网页中的脚本文件,并删除不必要的脚本。只保留必要的脚本,可以减少下载和执行脚本的时间,从而降低输入延迟。

  4. 使用延迟(defer)加载或异步(async)加载:对于某些脚本,我们可以将其设置为延迟(defer)加载或异步(async)加载,以便在页面加载完成后再加载和执行。这样可以防止脚本的下载和执行阻塞页面的呈现和用户交互。


8. 测量FID

可以使用以下工具的字段数据来分析首次输入延迟(FID):

  1. 使用Chrome用户体验报告
  2. PageSpeed Insights
  3. Search Console
  4. Firebase性能监测

如何使用JavaScript测量FID?

我们还可以通过在页面中添加JavaScript代码来测量FID。

有两种方法可以实现这一点:

  1. 使用web-vitals JavaScript库。
shell 复制代码
npm install web-vitals
或
yarn add web-vitals

将以下代码添加到我们的页面中,以在控制台中输出FID值:

javascript 复制代码
import {onLCP, onFID, onCLS} from 'web-vitals';

onCLS(console.log);
onFID(console.log);
onLCP(console.log);

关于web-vitals的更多用法,可以参考其官网

  1. 手动添加PerformanceObserver以跟踪输入。 如果我们不想导入web-vitals库,还可以手动使用Event Timing API来跟踪FID。
javascript 复制代码
let firstHiddenTime = document.visibilityState === 'hidden' ? 0 : Infinity;
document.addEventListener('visibilitychange', (event) => {
  firstHiddenTime = Math.min(firstHiddenTime, event.timeStamp);
}, {once: true});

function sendToAnalytics(data) {
  const body = JSON.stringify(data);
  (navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
      fetch('/analytics', {body, method: 'POST', keepalive: true});
}

try {
  function onFirstInputEntry(entry, po) {
    if (entry.startTime < firstHiddenTime) {
      const fid = entry.processingStart - entry.startTime;
      po.disconnect();
      sendToAnalytics({fid});
    }
  }

  const po = new PerformanceObserver((entryList, po) => {
    entryList.getEntries().forEach((entry) => onFirstInputEntry(entry, po));
  });

  po.observe({
    type: 'first-input',
    buffered: true,
  });
} catch (e) {
}

上面代码用于收集FID数据,并将其发送到分析服务。

  1. 首先,代码初始化一个名为 firstHiddenTime 的变量。

    • 它通过检查当前页面的 visibilityState 是否为 'hidden' 来判断页面是否已隐藏。
    • 如果页面已隐藏,将 firstHiddenTime 设置为 0,否则设置为无穷大(Infinity)。
    • 这样做是为了记录页面首次隐藏的时间,即用户切换到其他标签页或最小化浏览器的时间。
  2. 通过添加 visibilitychange 事件监听器,当页面的可见性状态发生变化时,触发回调函数。

    • 这里使用了 { once: true } 参数,使回调函数只执行一次。
    • 在回调函数中,将当前事件的时间戳(event.timeStamp)与 firstHiddenTime 比较,并将较小的值更新为 firstHiddenTime
    • 这样,firstHiddenTime 将记录页面的首次隐藏时间。
  3. 定义了一个名为 sendToAnalytics 的函数,用于将数据发送到分析服务。

    • 函数接受一个 data 参数,它是要发送的数据。
    • 数据会被序列化为 JSON 字符串,并通过 navigator.sendBeacon 方法异步发送到 '/analytics' 接口。
    • 如果浏览器不支持 sendBeacon 方法,则使用 fetch 方法以 POST 请求的方式发送数据,并通过 keepalive: true 选项保持请求的持久连接。
  4. try 块中,定义了一个名为 onFirstInputEntry 的函数,它用于处理 PerformanceObserver 观察到的首次输入(FID)性能条目。

    • 首次输入是指用户首次与页面交互(例如点击按钮)时,浏览器开始处理输入事件到实际响应的延迟时间。
  5. 创建了一个 PerformanceObserver 对象 po,用于观察页面性能条目,并设置 type 为 'first-input' 并启用 buffered: true 选项,这样可以缓冲已有的性能条目。这使得我们能够获取到首次输入的性能条目。

  6. PerformanceObserver 的回调函数中,使用 entryList.getEntries() 获取到所有的性能条目,并遍历处理这些条目。

    • 对于每个性能条目,我们检查它的 startTime 是否在页面首次隐藏时间 firstHiddenTime 之前,如果是,则计算首次输入的延迟时间(fid),并调用 sendToAnalytics 函数将其发送到分析服务。

9. 最大潜在首次输入延迟(Max Potential First Input Delay)

根据用户首次与页面进行交互的时间,FID可能会有很大的差异,因为浏览器的主线程在页面的生命周期中并不是均衡占用的。因此,一些用户可能根本不会遇到延迟,而其他用户可能会因此感到非常不满意,这取决于他们首次与页面进行交互的时间。

因此,监测页面的最大潜在首次输入延迟(MPFID)可能会有所帮助。它是在FCP后在主线程上运行的最长任务的持续时间

通过测量该任务的持续时间,可以模拟用户在这个长时间任务开始时与页面进行交互,并等待任务完成以处理输入的潜在情况。

优化MPFID涉及多种策略,可以减少最长任务的运行时间或将其分解为较小的块。

MPFID是Lighthouse中的一个实验室指标。要查看它,可以将我们页面的Lighthouse报告导出为JSON文件。

然后,我们可以通过Lighthouse Viewer对报告进行查看。


10. 能否在Lighthouse测量 FID ?

答案是不能的 ,我们不能使用像Lighthouse这样的实验室工具 来测量FID这种真实用户指标

要注册输入事件,需要实际用户的交互。然而,我们可以借助与FID强相关的指标 进行分析和测量。 起到了,隔山打牛的作用。

总阻塞时间(Total Blocking Time,TBT)是一个在实验室中可以测量的指标示例。如果我们改善了TBT,很可能也会改善FID

TBT测量了从FCP可交互时间(Time To Interactive)期间,主线程因无法响应用户输入而被阻塞的时间。

通过改善TBT,我们很可能也会改善首次输入延迟的表现。


后记

分享是一种态度

全文完,既然看到这里了,如果觉得不错,随手点个赞和"在看"吧。

相关推荐
前端小小王7 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发16 分钟前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
娃哈哈哈哈呀38 分钟前
vue中的css深度选择器v-deep 配合!important
前端·css·vue.js
旭东怪1 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
ekskef_sef3 小时前
32岁前端干了8年,是继续做前端开发,还是转其它工作
前端
sunshine6413 小时前
【CSS】实现tag选中对钩样式
前端·css·css3
真滴book理喻3 小时前
Vue(四)
前端·javascript·vue.js
蜜獾云3 小时前
npm淘宝镜像
前端·npm·node.js
dz88i83 小时前
修改npm镜像源
前端·npm·node.js
Jiaberrr4 小时前
解锁 GitBook 的奥秘:从入门到精通之旅
前端·gitbook