由于 FID 需要一个真实用户的交互,所以无法用实验数据测试。

为了在实验数据下预测 FID ,通常会用 TBT(Total Blocking Time) ,具体这个指标后面文章会介绍。他们测量的内容不同,但改善 TBT 通常也能改善 FID

一个糟糕的 FID 主要原因是JS执行过长,优化JS的解析、编译、执行可以直接降低 FID

过长的JS执行

当JS执行过程中,浏览器无法响应用户交互,因为主线程被占用,为了改善这点,可以:

  • 分解长任务
  • 优化页面,为交互准备
  • 使用 Web Worker
  • 减少JS执行时间

分解长任务

如果你准备尝试减少单个页面的js的体积,可以先考虑把较长执行的js代码分解成小的异步任务。

长任务指的是用户可能会发现页面无响应的时期执行的js代码。任何阻塞主线程大于等于50ms的代码都是长任务。长任务一般是js体积过大的潜在因素(浏览器加载并执行了比页面初始化所需要的更多的js)。

分解长任务可以降低用户输入延迟。

当你采用最佳实践(例如拆分代码、分解长任务), FID 会有显著改善。虽然 TBT 并非现场数据指标,但这对于改善 FID TTI(Time To Interactive) 都很有帮助。

优化页面,为交互准备

造成 FID TBT 分数低有很多原因,大多都是js引起的。

自己站点的脚本执行可能会延后交互

  • JS体积过大,执行时间过长,无效的分包会导致页面响应用户交互变慢,影响 FID TBT TTI 。逐步加载代码和功能块可以拆分这些任务,提升响应速度。
  • 服务端渲染看上去页面是出来了,但用户的交互还是受限于js的执行时间,可以考虑把更多逻辑代码放在服务端实现,或者在构建的时候创建更多静态内容。

下图是 TBT 得分的优化前后对比。通过将非必须的昂贵的脚本的加载和执行移出关键路径,用户就可以更快的去与页面交互。

数据获取会影响交互准备的很多方面

  • 级联的获取数据的水流图(包含js,数据的网络请求等),会导致交互延迟。目的是要减少对级联数据获取的依赖。(减少请求数)
  • 较大的内联数据可以节省HTML的解析时间,同时影响绘制图像和交互两种指标。目的是要减少客户端后续处理对数据的依赖。(数据在内联已经准备好了,不需要额外请求)

第三方脚本的执行可能会延后交互

  • 很多网站都包含第三方库的标签和统计代码,这些会导致网络阻塞,使得主线程长时间无法响应,延后了交互。查找出必须加载的第三方代码。(例如:不滚动到指定位置不展示广告)
  • 有时候,第三方的脚本会抢先于本站脚本加载,例如加载优先级和带宽限制。尝试着优先加载你觉得可以给用户提供最有价值的东西。

使用 web worker

主线程阻塞是导致输入延迟的主要因素之一。web worker可以让你的代码在后台进程中执行,把一些非UI的操作放在web worker中执行可以减少主线程压力,改善 FID 指标。

可以使用以下的库,让你的站点更方便的集成web worker:

减少JS执行时间

  • 延后加载未使用的js
  • 最小化无用的polyfill

延后加载未使用的js

通过开发者工具中的coverage的tab页可以查看各资源的有效使用率。

为了减少无用JS,可以:

  • 把你的代码拆分成多个chunk,按需加载
  • 使用 async 或者 defer 延后加载非关键脚本,包含第三方脚本

代码拆分指的是将一个大的单个JS拆分成多个小的,根据条件去加载对应的JS。现代浏览器已经支持按需加载:

import('module.js')	
  .then((module) => {	
    // Do something with the module.	
  });

除了常用浏览器支持以外,一些构建系统也支持:

  • webpack,rollup,parcel等构建工具
  • angular,react,vue等客户端框架

除了可以使用代码拆分,也可以使用 async 或者 defer 来延后加载非关键脚本。

<script defer src=""></script>	
<script async src=""></script>	

除非有特殊原因,一般第三方脚本都可以默认采用这种方式加载。

最小化无用的polyfill

如果你用了一些js高级语法,你可能需要将这些代码转换成旧版浏览器支持的语法,或者引入polyfill来支持。

最好的做法是,如果浏览器支持这些语法,不引入polyfill。最小化无用的polyfill,并且将它们的使用限制在需要它们的环境中,可以降低js的体积。

优化polyfill的使用,可以:

  • 如果你是用babel转义,使用 @babel/preset-env 可以只包含你需要支持的浏览器的polyfill。对于babel 7.9,可以开启 bugfixes 配置,进一步减少无用的polyfill。
  • 使用 module/nomodule 的模式传输两份不同的bundle。(@babel/preset-env 也支持,可以通过 target.esmodules
<script type="module" src="modern.js"></script>	
<script nomodule src="legacy.js" defer></script>	

这样可以保证支持js模块的浏览器,可以加载模块化的打包文件,不支持的浏览器可以加载转义后的打包文件。

开发者工具

Lighthouse 6.0 不能测试 FID,因为它是一个现场数据指标,但是 TBT 可以作为替代品测试。针对 TBT 的优化项对 FID 也同样有效。

实际项目的优化需要频繁的使用开发者工具 performance 和 lighthouse。针对长任务进行拆解,针对未使用的js进行移除,针对复杂的js使用web worker。最后再针对旧版浏览器和新版浏览器加载不同资源,以保证新版浏览器的对polyfill更少的依赖。如果使用webpack打包的项目,可以查看打包的分布图,针对性的去优化每一个bundle。

https://web.dev/optimize-fid/

由于 FID 需要一个真实用户的交互,所以无法用实验数据测试。为了在实验数据下预测 FID,通常会用 TBT(Total Blocking Time),具体这个指标后面文章会介绍。他们测量的内容不同,但改善 TBT 通常也能改善 FID。一个糟糕的 FID 主要原因是JS执行过长,优化JS的解析、编译、执行可以直接降低 FID。过长的JS执行当JS执行过程中,浏览器无法响应用户交互,因为主线程被占用,为了改善这点,可以:分解长任务优化页面,为交互准备使用 Web Worker减少JS执行
众所周知,第一印象很重要,不仅是在与人交流上,在构建web体验的时候也是如此。 在web上,一个好的第一印象是决定用户去留的关键。那么问题来了,怎样才能留下好的第一印象,怎样测试你的网站给用户留下的第一印象? 在web上,第一印象也分很多方面:站点设计、视觉体验、速度和响应。 很难用API去测试一个网站的设计和视觉,但却可以测试速度和响应。 测试你的站点给用户的第一印象加载多快,可以通过 FCP 的指标。但在屏幕上绘制像素仅仅是这个故事的一部分,同样重要的,还有你的网站对用户的交互响应有多快。 FID(Fi
passive:不会对浏览器的默认行为说No 这个修订是为了扩展新的选项,从而自定义更多的行为,目前规范中 options 对象可用的属性有三个: addEventListener(type, listener, { capture: false, passive: false, once: false 三个属性都是布尔类型的开关,默认值都为 false。其中 capture 属性等价于以前的 useCapture 参数;once 属性就是表明该监听器是一次性的,执行一次后就
之前整理过一份分析Performance的博文: 利用Performance API分析网站性能 这次还是拿CSDN的performance来举例说明, 这几个名词的含义, 供自己遗忘和不会的同学方便查看 FP (First Paint) 首次绘制: 标记浏览器渲染任何在视觉上不同于导航前屏幕内容之内容的时间点. FCP (First Contentful Paint) 首次内容绘制 标记浏览...
总阻塞时间 (TBT) 是测量加载响应度的重要实验室指标,因为该项指标有助于量化在页面交互性变为可靠前,不可交互程度的严重性,较低的 TBT 有助于确保页面的可用性。 什么是 TBT?# 总阻塞时间 (TBT) 指标测量First Contentful Paint 首次内容绘制 (FCP)与Time to Interactive 可交互时间 (TTI)之间的总时间,这期间,主线程被阻塞的时间过长,无法作出输入响应。 每当出现长任务(在主线程上运行超过 50 毫秒的任务)时,主线程都被视作"阻塞状态".
减少DOM节点数量:当遍历查询500和5000个DOM节点,进行事件绑定时,会有所差别。 当一个页面DOM节点过多,应该考虑使用无限滚动方案来使视窗节点可控(视频列表使用滑动窗口)。 减少cookie大小:cookie 传输会造成带宽浪费,影响响应时间。消除不必要的cookies; 静态资源不需要 c....
数组中的find、filter、forEach、map四个语法很相近,为了方便记忆,真正的掌握它们的用法,所以就把它们总结在一起喽。 find():返回通过测试的数组的第一个元素的值 在第一次调用 callback 函数时会确定元素的索引范围,因此在 find 方法开始执行之后添加到数组的新元素将不会被 callback 函数访问到。如果数组中一个尚未被callback函数访问到的元素的值被c...
首先简单的介绍一下ES6是什么,可能很多人还是第一次听说,我们都知道H5是html的新一代的标准,同样,ES6是javascript的新一代标准,全称是ECMAScript 6.0,简称ES6,其实不是什么神秘的东西。15年6月发布的。 今天我们要说的是结合ES6新特性谈一下js里面的一个很好用的方法-find() 现在的前端和过去的不一样,过去的前端只要会画页面就行了,但是现在仅仅会画页面已...
本篇是基于 FDCon2019 上《让你的网页更丝滑by刘博文》的复盘文。该课题也是博主感兴趣的领域, 后续会结合 React 的 Schedule 与该文进行进一步整合, 个人博客 被动交互: animation 主动交互: 鼠标、键盘 被动交互 当前市面上的设备频率在 60 HZ 以上。 主动交互 跑如下界面 code.h5jun.com/pojob 结合如下代码块, 可以看到...
前端性能优化及其度量方法 前端页面性能对用户留存、用户直观体验有着重要影响,当页面加载时间超过 2 秒后,加载时间每增加一秒,就会有大量的用户流失,所以做好页面性能优化,对网站来说是一个非常重要的步骤。 提到性能优化,灵魂三问来啦,什么是前端性能优化?如何度量前端性能?如何做性能优化?一个页面的性能指标非常多,面对一大堆性能指标,可能一个老手也一时间不知道从何开始分析,所以本篇文章我会介绍一些性能优化最基础的知识点和工具,以及根据工作分析出数据如何做性能优化,并推荐几个公司个性化需求改造后的性能检测工具。