因为 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 并非现场数据指标,但这对于改善 FIDTTI(Time To Interactive) 都很有帮忙。

优化页面,为交互筹备

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

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

  • JS体积过大,执行工夫过长,有效的分包会导致页面响应用户交互变慢,影响 FIDTBTTTI。逐渐加载代码和功能块能够拆分这些工作,晋升响应速度。
  • 服务端渲染看上去页面是进去了,但用户的交互还是受限于js的执行工夫,能够思考把更多逻辑代码放在服务端实现,或者在构建的时候创立更多动态内容。

下图是 TBT 得分的优化前后比照。通过将非必须的低廉的脚本的加载和执行移出要害门路,用户就能够更快的去与页面交互。

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

  • 级联的获取数据的水流图(蕴含js,数据的网络申请等),会导致交互提早。目标是要缩小对级联数据获取的依赖。(缩小申请数)
  • 较大的内联数据能够节俭HTML的解析工夫,同时影响绘制图像和交互两种指标。目标是要缩小客户端后续解决对数据的依赖。(数据在内联曾经筹备好了,不须要额定申请)

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

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

应用 web worker

主线程阻塞是导致输出提早的次要因素之一。web worker能够让你的代码在后盾过程中执行,把一些非UI的操作放在web worker中执行能够缩小主线程压力,改善 FID 指标。

能够应用以下的库,让你的站点更不便的集成web worker:

  • Comlink
  • Workway
  • Workerize

缩小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/