1 背景
上一篇,介绍了,前端性能的主要指标,以及如何获取的方法,链接如下:
使用chatGPT,设计一套可落地的前端性能优化方案(上) - 掘金 (juejin.cn)
在调研方案的同时也做了一张脑图
本篇呢,继续上一篇的内容,在分析优化方案的时候我们定两个主要方向:
- 编译时 —— 构建工具打包时的优化(我主要站webpack队的,以下优化方案,如果没有特别说明,均是webpack方案)
- 运行时 —— 用户从输入URL到展示
以FCP为例,大概是这样
由于篇幅有限,可能要分成多章来写,各位见谅
2 指标以及对应的优化方案
根据最新的chrome Lighthouse规则,前端的性能指标主要有:
- FCP(First Contenful Paint):首次内容绘制时间,即浏览器首次绘制任何文本、图像、非空白canvas或SVG的时间。
- SI(Speed Index):速度指数,即页面渲染速度的指标。
- LCP(Largest Contentful Paint):最大内容绘制时间,即页面中最大的可见内容元素绘制完成的时间。
- TBT(Total Blocking Time):总阻塞时间,即页面主线程被阻塞的总时间。
- CLS(Cumulative Layout Shift):累计布局偏移,即页面上所有元素在视觉上发生的意外移动的总和。
- TTI(Time to Interactive)TTI是指页面变得可交互所需的时间
- TTD(Time to Display)TTD是指页面显示所需的时间
2.1 FCP(First Contenful Paint)的优化方案
问题:如何优化 FCP(First Contenful Paint)
优化目标:FCP 1.8s以内,具体方法:
根据new bing第一个回答,接下来我会用大量的问题,得到每一个优化点的答案
由于接下来问题较多,我就不一一截图了,按照编译时和运行时给大家总结一下。
与new bing交互的问题汇总:
-
如何移除渲染阻塞资源
-
webpack如何,异步加载或延迟加载JavaScript文件
-
如何做到 在拉入CSS文件的链接元素上使用media属性,以识别有条件的CSS资源,即仅特定设备或情况所需的CSS资源
-
什么是内联首屏关键CSS
-
webpack 实现 Critical Path CSS Generator
-
webpack 移除未使用的CSS代码
-
如何在字体加载之前和期间显示文本
-
针对font-display举个例子
-
webpack 极简化 HTML、CSS 和 JavaScript 文件
-
如何减少 TTFB(Time-To-First-Byte)
-
前端如何优化CDN
-
nginx TLS开销优化
优化点1、异步加载或延迟加载JavaScript文件,让浏览器在解析HTML的同时下载JavaScript,而不是暂停解析:
编译时:
- 使用 entry 配置手动地分离代码,指定多个入口文件,每个入口文件对应一个 bundle。这种方式需要手动管理依赖关系,防止重复打包。
- 使用 import() 或 require.ensure() 动态地分离代码,让 Webpack 自动地根据代码中的 import() 或 require.ensure() 语句进行代码分割,生成一个或多个 chunk。这种方式可以实现按需加载或懒加载,提高性能和用户体验。
运行时:
-
使用async属性,让浏览器在下载JavaScript时继续解析HTML,但是一旦下载完成,就会暂停解析并执行脚本。这种方法适用于不依赖其他脚本的独立运行的脚本,因为它们的执行顺序是不确定的。
-
使用defer属性,让浏览器在下载JavaScript时继续解析HTML,并且等待执行脚本,直到HTML解析完成。这种方法可以保证脚本按照它们在页面中出现的顺序执行,适用于需要等待页面解析和依赖其他脚本的情况。
-
动态创建DOM元素,通过JavaScript代码创建一个script标签,并设置其src属性为要加载的脚本文件,然后将其添加到文档中。这种方法可以在任何时候动态地加载和执行脚本,但是需要注意控制好加载时机和依赖关系。
-
使用setTimeout延迟方法,它可以接受一个函数和一个时间间隔作为参数,并在指定的时间间隔后执行该函数。这种方法可以用来模拟异步加载的效果,但是需要注意不要设置过长或过短的时间间隔,以免影响用户体验或造成错误。
-
让js最后加载,即将script标签放在body标签的最后面,这样可以确保在加载和执行js之前,页面的其他内容已经呈现出来。这种方法是最简单和最常用的一种,但是也有一些缺点,比如无法控制多个脚本之间的依赖关系,以及无法利用浏览器的并行下载能力。
优化点2、在拉入CSS文件的链接元素上使用media属性,以识别有条件的CSS资源,即仅特定设备或情况所需的CSS资源
运行时
在 link 元素上使用 media 属性,可以指定该元素链接的样式表或其他资源适用于哪些媒体类型或媒体查询。这样可以让浏览器根据当前的设备或情况,选择性地加载或应用不同的资源,从而提高性能和用户体验。
media 属性的值可以是一个媒体类型,如 screen, print, all 等,表示该资源只适用于特定的媒体类型。也可以是一个媒体查询,如 (max-width: 600px), (orientation: portrait) 等,表示该资源只适用于满足媒体查询条件的情况。
例如,如果你想让一个样式表只在打印时生效,你可以这样写:
<link href="print.css" rel="stylesheet" media="print">
如果你想让一个样式表只在屏幕宽度小于 600px 时生效,你可以这样写:
<link href="mobile.css" rel="stylesheet" media="screen and (max-width: 600px)">
优化点3、确定呈现首屏内容所需的样式,并与HTML内联发送这些样式,避免使用@import引入CSS
编译时
webpack 实现 Critical Path CSS Generator 的一种方法是使用critters-webpack-plugin,这是一个webpack插件,可以内联你的应用的关键路径CSS,并延迟加载剩余的CSS。它的工作原理是:你在webpack配置中添加这个插件,并设置一些可选的配置项,然后它会自动处理你的HTML文件,将关键路径CSS内联到head标签中,并将其他CSS文件通过JS异步加载。这样可以提高网页渲染的速度和用户体验。
运行时
内联首屏关键CSS(Critical CSS)是指对网站首屏内容进行样式设计的CSS,并将其放在HTML的head标签中的style标签里,这样可以减少HTTP请求和渲染阻塞,提高页面的加载速度和用户体验。这种方法可以利用一些工具来实现,比如 Critical Path CSS Generator 。
优化点4、移除未使用的CSS代码,避免加载不必要的样式
编译时
使用webpack移除未使用的CSS代码。您可以使用以下步骤:
安装purgecss-webpack-plugin模块,这是一个webpack插件,可以分析您的HTML和JavaScript文件,并从CSS文件中删除未使用的样式。
在webpack配置文件中引入purgecss-webpack-plugin和glob模块,glob模块可以帮助您指定要分析的HTML文件路径。
在plugins数组中添加一个PurgecssPlugin实例,并传入一个对象,该对象包含paths属性,该属性是一个数组,包含您要扫描的所有HTML文件的路径。您可以使用glob.sync方法来动态生成这个数组。 运行webpack打包命令,您的CSS文件将被优化,去除了无用的代码。
优化点5、使用优化和压缩过的图像、SVG 或 WebP 格式的图像
这个感觉跟前端关系不大,这里就不过多讨论了,感兴趣的同学自己研究一下吧
优化点6、在字体加载之前和期间,显示文本
运行时
使用 CSS 的 font-display 属性来控制字体加载和替换的行为123。font-display 可以取不同的值,如 auto, block, swap, fallback 或 optional,它们会影响浏览器在字体加载期间如何显示后备字体或空白。
font-display 可以控制字体加载和替换的行为。它有四个常用的值,分别是 swap, block, fallback 和 optional,它们会影响浏览器在字体加载期间如何显示后备字体或空白
@font-face {
font-family: 'MyWebFont';
src: url('myfont.woff2') format('woff2'),
url('myfont.woff') format('woff');
font-display: swap;
}
优化点7、极简化 HTML、CSS 和 JavaScript 文件,去除无关的字符和空格,减小文件大小
编译时
代码压缩,这是一个很平常的功能了,webpack 5在mode为production时会自动开启压缩,主要使用的是下面两个插件:
- css-minimizer-webpack-plugin:用于优化和压缩 CSS 文件
- terser-webpack-plugin:用于压缩 JavaScript 文件
优化点8、 减少 TTFB(Time-To-First-Byte),即服务器响应请求的时间,这取决于您的服务器主机、CDN 和浏览器缓存等因素。
- 使用内容分发网络(CDN),把网站内容缓存到离用户更近的节点上,减少网络延迟
选择合适的CDN服务商,根据网站的目标用户和流量分布,选择有覆盖范围广、节点多、速度快、价格合理的CDN服务商,比如国外的Google Cloud CDN、Cloudflare等,国内的阿里云CDN、腾讯云CDN等。
配置CDN缓存策略,根据静态资源的更新频率和有效期,设置合理的缓存时间和过期时间,避免缓存过期导致重新请求源站,也避免缓存过久导致资源过时。
启用CDN压缩功能,让CDN节点对静态资源进行压缩,减少传输的数据量,提高传输速度。一般可以使用Gzip或Brotli等压缩算法。
启用CDN HTTPS功能,让CDN节点支持HTTPS协议,提高网站的安全性和信任度,同时也可以利用HTTP/2的优势,比如多路复用、头部压缩、服务器推送等。
启用CDN预取功能,让CDN节点主动从源站获取一些热门或重要的静态资源,提前缓存到节点上,减少用户请求时的等待时间。
- 使用高级DNS服务,通过使用DNS服务器的全球网络以低延迟回答DNS查询,从而帮助您减少TTFB。这个与前端关系不大,而且需要额外的费用,简单了解一下:
高级DNS服务的特点有:
- 使用全球分布的DNS服务器,让用户可以就近访问,减少网络延迟和距离。
- 使用Anycast网络,提供多层冗余,防止单点故障和DDoS攻击,保证DNS的正常运行。
- 使用DNSSEC技术,保护DNS查询过程的安全性,防止黑客篡改或伪造DNS响应。
- 使用辅助DNS功能,同步主DNS服务器的数据,提高DNS的可靠性和容灾能力。
- 提供易于管理的控制面板,让用户可以轻松创建、修改、删除DNS记录,设置缓存策略和模板等。
使用高级DNS服务可以为网站带来以下好处:
- 加快网站的加载速度,提高用户体验和满意度。
- 降低网站的跳出率和流失率,提高转化率和收益。
- 增强网站的安全性和信誉,避免黑客攻击和钓鱼诈骗。
- 提升网站的SEO排名,吸引更多的流量和客户。
- 部署上采用,nginx TLS开销优化。这个跟前端关系也不是很大,稍微了解一下
- 开启HTTP/2协议,利用其二进制格式、多路复用、头部压缩等特性,提升性能,尤其是需要并行多个请求的时候可以显著减少延迟。
- 调整Cipher优先级,尽量选择更新更快的Cipher,有助于减少延迟。
- 启用OCSP Stapling,将CA签名的OCSP响应附加到TLS握手中,避免客户端单独联系CA进行证书验证,减少网络延迟和距离。
- 调整SSL会话缓存,使用共享内存或者文件缓存SSL会话参数,避免重复的TLS握手过程,提高连接速度。
- 启用SSL会话票据,使用加密票据缓存SSL会话参数,避免重复的TLS握手过程,提高连接速度。
- 启用TCP Fast Open,使用TCP选项携带数据,在三次握手过程中就开始传输数据,减少网络延迟。
- 启用TCP Keepalive,使用TCP选项保持连接活跃,在空闲时发送心跳包,避免重新建立连接的开销。
3、小结
好的针对FCP的优化,应该就这些了,其实上面的回答,还有很多可以追问的点,但各位同学没有必要较真,还记得我们优化最开始时的目标么。
FCP 1.8s以内,也就是performance.getEntriesByType('navigation')[0].responseStart的值小于1800ms
大多数情况下,我们用webpack的插件做好拆分,上了CDN就可以达到了,当然了如果为了KPI我们可以适当的提高目标,适当的用一些里面的优化手段,来完成KPI目标也未尝不可。
由于篇幅所限,其他的性能指标放在下一篇来分享
本文正在参加 人工智能创作者扶持计划