实践指南-前端性能提升 270% | 京东云技术团队
一、背景
当我们疲于开发一个接一个的需求时,很容易忘记去关注网站的性能,到了某一个节点,猛地发现,随着越来越多代码的堆积,网站变得越来越慢。
本文就是从这样的一个背景出发,着手优化网站的前端性能,并总结出一套开发习惯,让我们在日常开发时,也保持高性能,而不是又一次回过头来优化性能。
指标名称 | 优化前 | 优化后 | 提升 |
---|---|---|---|
Lighthouse Performance 评分 | 29 | 81 | 279% |
FCP(First Contentful Paint 首次内容绘制) | 0.7s | 0.7s | |
LCP(Largest Contentful Paint 最大内容绘制) | 6.2s | 2.5s | 248% |
TTI(Time to Interactive 可交互时间) | 10.1s | 2.1s | 480% |
Speed Index(速度指数) | 5.6s | 1.8 | 311% |
TBT(Total Blocking Time 总阻塞时间) | 820ms | 120ms | 683% |
优化前后对比:
二、优化前
接下来就是介绍下优化前我们要做哪些事件:
-
了解性能指标及测量工具
-
分析需要优化的地方
1. 了解测量工具及性能指标
一开始我们只是感受到网站的页面打开时白屏时间较长,感觉性能是比较差的,那么具体有哪些性能指标需要去关注呢?
这里我使用的是 Chrome devtools 内置的Lighthouse,Lighthouse 是一种开源的自动化工具,用于提高 Web 应用程序的质量。
Lighthouse 会在一系列的测试下运行网页,比如不同尺寸的设备和不同的网络速度。它还会检查页面对辅助功能指南的一致性,例如颜色对比度和 ARIA 最佳实践。
打开 Chrome devtools Lighthouse 即可使用。
在比较短的时间内,Lighthouse 可以给出这样一份报告。
这份报告从 5 个方面来分析页面: 性能、辅助功能、最佳实践、搜索引擎优化和 PWA。像性能方面,会给出一些常见的耗时统计。
1.1 Performance
Performance 评分统计,包括了以下指标:
1.1.1 FCP
FCP 测量在用户导航到页面后浏览器呈现第一段 DOM 内容所花费的时间。页面上的图像、非白色<canvas>
元素和 SVG 被视为 DOM 内容;不包括 iframe 内的任何内容。
1.1.2 LCP
LCP 测量视口中最大的内容元素何时呈现到屏幕上。这近似于页面的主要内容对用户可见的时间。
需要注意的是 LCP 的计算是一个动态的过程,如下图最后的图片才是这个页面中的最大内容绘制的元素。
1.1.3 TTI
TTI 测量页面完全交互所需的时间。
TTI 是如何计算的呢,如下图首先延时间轴正向搜索时长至少为 5 秒的安静窗口(安静窗口是指没有长任务且不超过两个正在处理的网络 get 请求),然后沿时间轴反向搜索安静窗口之前的最后一个长任务,如果没有找到长任务,则在 FCP 步骤停止执行,TTI 就是安静窗口之前最后一个长任务的结束时间,如果没有找到长任务的话,则与 FCP 值相同。
1.1.4 Speed Index
Speed Index 衡量页面加载期间内容以视觉方式显示的速度。Lighthouse 首先捕获浏览器中页面加载的视频,并计算帧之间的视觉进度。
1.1.5 TBT
TBT 测量页面被阻止响应用户输入(例如鼠标点击、屏幕点击或键盘按下)的总时间。
通过添加 First Contentful Paint 和 Time to Interactive 之间所有长任务的阻塞部分来计算总和。任何执行时间超过 50 毫秒的任务都是长任务。
50 毫秒后的时间量是阻塞部分。例如,如果 Lighthouse 检测到一个 70 毫秒长的任务,则阻塞部分将为 20 毫秒。
如下图淡红色区域的时间总和就是这个页面的 TBT 分数。
1.2 最佳实践
用于检测 Web 应用程序整体代码健康状况,包括是否包含文档类型、图片宽高比是否正确等等。
1.3 SEO
用于检测搜索引擎对网页内容的理解程度。
2. 分析需要优化的地方
了解了关键的性能指标后,就可以测量看看当前网站的性能了,
上面看到综合评分是非常低的,Lighthouse 给出了应该从哪些地方开始优化的建议。
2.1 Performance
性能优化建议主要包括以下几点:
-
减少未使用的 JS;
-
合理使用图片的格式,webp 或者 avif 更快;
-
延迟加载不在视图的图片;
-
JS 压缩;
-
图片的尺寸大小应该适当;
-
减少未使用的 CSS。
Lighthouse 诊断出的网站存在的问题:
-
需要加载的资源太多太大,有 147 个请求,合计 11mb;
-
有 40 个静态资源的缓存只有 1 小时
-
滚动事件没有添加标记
{passive: true})
,导致需要等待侦听器完成执行后再滚动页面; -
图像元素没有设置明确的宽度和高度;
-
JS 文件太多,主线程工作量太大、JS 执行时间太长;
2.2 最佳实践
最佳实践方面有以下问题:
-
图片的分辨率太低,清晰度不够;
-
没有设置 CSP 策略。
2.3 SEO
SEO 有以下问题:
-
没有 meta description;
-
图片没有 alt 属性;
-
robots.txt 是无效的。
三、优化 Performance
根据上面 Lighthouse 报告,捋一捋项目中影响性能最大的因素,包括以下几点:
-
体积太大,达 11mb;
-
图片太大,图片格式也有影响。
1. 体积优化
1.1 代码压缩
检查是否还有压缩空间,或者有无工具库未压缩的。
1.2 代码分包
通过 webpack-bundle-analyzer 插件分析包体积,将一些大的 npm 包和 runtimeChunk 独立分包,减小包体积。
1.3 组件按需加载
React.lazy + Suspense 封装懒加载组件,路由级组件引入懒加载组件。
同时使用骨架屏作为懒加载的兜底组件,可以让用户感知加载更快。
在鼠标移入导航栏时预加载路由组件,可以加快页面展示。
1.4 工具库按需加载
通过 import(‘xx’).then(xx) 按需加载工具库。
1.5 静态资源上传 CDN
项目内有一些 json 文件存储的静态数据,这部分文件上传至 CDN,改为 fetch 的方式按需引入。
1.6 删除不需要的资源
检查项目中引入的 mf、npm 资源,将没有使用到的删除。
1.7 避免重复的 npm 包引入
发现业务组件库通过 npm 引入的原子组件库,而项目本身又是通过 mf 引入的原子组件库,相对于引入了 2 遍原子组件库。
这时就需要改造业务组件库,也改成用 mf 的方法引入。
1.8 避免 esm 依赖嵌套
因为 webpack 的按需加载是通过 import、export 来标记的,因此想要一个好的按需加载的效果,就需要避免依赖嵌套的问题。
1.9 图标按需加载
原子组件库 mf 暴露的方式会导致只用了 1 个 icon,就会加载组件库下所有 icon 对应的 chunk,导致资源浪费。
新建一个 icon 的 npm 包用于 icon 的按需引入。
1.10 小结
通过以上优化手段,体积从 11.7mb 降低至 1.1mb,降低 10.6 倍。
优化前:
优化后:
2. 图片优化
1.1 图片懒加载
对非首屏的图片采用图片懒加载策略。
1.2 图片尺寸
使用图片时,设置图片的合理尺寸。
1.3 图片格式设置
优先使用 webp 格式图片。
四、优化最佳实践
1. 设置 CSP 策略
2. 设置合理的图片的分辨率
优化项目内的图片分辨率。
五、优化 SEO
1. meta description、keywords 优化
详细的 meta description、keywords 可以加快 SEO。
<meta name="keywords" content="xx" /> <meta name="description" content="xx" />
2. 图片加上 alt 属性
<img src="smiley.gif" alt="Smiley face" />
六、优化前后对比
再来回顾下前后对比:
优化前,明显的感知白屏时间长:
优化后,在清缓存的情况下也能实现秒开:
整体性能提升 270%:
七、性能监控
为了在后续的迭代过程中,保持高性能,引入内部前端监控平台 -烛龙,可视化的监控前端性能。
第一步,加载 cdn 插件:
<scriptdefersrc="https://h5static.m.jd.com/act/jd-jssdk/latest/jd-jssdk.min.js"
></script>
第二步,在入口文件中,初始化 cdn 插件:
useEffect(() => {// 初始化测速组件,在这里可以打开一些控制的开关,如是否上报接口if (IS_PROD) {// @ts-ignorejmfe.profilerInit({flag: xxx, // 这是应用ID,需要先在烛龙申请应用autoReport: true,autoAddStaticReport: true,autoAddApiReport: true,autoAddImageReport: false, // 支持所有图片上报,如果图片多,切记关闭,否则存在性能问题performanceReportTime: 8000,profilingRate: 1,})}
}, [])
第三步,查看监控数据:
在烛龙平台,小工具性能评分达 96分:
第四步,新增告警,实时监控
烛龙平台支持多维度的告警的服务,增加性能指标相关的告警,在性能异动时,及时发现问题,优化性能。
小结
本文详细介绍了一个前端项目优化的详细过程,从优化前的问题分析,到具体的优化措施,最终实现了前端性能提升了近 3 倍。同时也将性能指标落到监控平台,实现可视化的监控前端性能指标。
希望能对你有所帮助,感谢阅读~
参考资料
- 被删的前端游乐场-前端性能优化-归纳篇
- 前端缓存 API 请求数据的解决方案
- 网易云课堂 Service Worker 运用与实践
作者:京东零售 唐姣
来源:京东云开发者社区
相关文章:

实践指南-前端性能提升 270% | 京东云技术团队
一、背景 当我们疲于开发一个接一个的需求时,很容易忘记去关注网站的性能,到了某一个节点,猛地发现,随着越来越多代码的堆积,网站变得越来越慢。 本文就是从这样的一个背景出发,着手优化网站的前端性能&a…...

8月11日上课内容 nginx的多实例和动静分离
多实例部署 在一台服务器上有多个tomcat的服务。 配置多实例之前,看单个实例是否访问正常。 1.安装好 jdk 2.安装 tomcat cd /opt tar zxvf apache-tomcat-9.0.16.tar.gz mkdir /usr/local/tomcat mv apache-tomcat-9.0.16 /usr/local/tomcat/tomcat1 cp -a /usr…...

腾讯云CVM服务器端口在安全组中打开!
腾讯云服务器CVM端口怎么开通?腾讯云服务器端口是通过配置安全组规则来开通的,腾讯云服务器网以开通80端口为例来详细说下腾讯云轻量应用服务器开启端口的方法,其他的端口的开通如8080、1433、443、3306、8888等端口也适用于此方法࿰…...
k8s、docker添加daemon.json添加“exec-opts“: [“native.cgroupdriver=systemd“]后无法启动的问题
考虑k8s下docker下载镜像太慢,修改了daemon.json,按照手册抄,添加 {"exec-opts": ["native.cgroupdriversystemd"],"registry-mirrors": ["https://kn0t2bca.mirror.aliyuncs.com"] }结果发现k8s起…...
React组件性能优化实践
React组件性能优化最佳实践 React组件性能优化的核心是减少渲染真实DOM节点的频率,减少 Virtual DOM比对的频率。 组件卸载前进行清理操作 在组件中为 window注册的全局事件,以及定时器,在组件卸载前要清理掉,防止组件卸载后继…...

SpringBoot复习:(29)静态资源的配置路径
WebMvcAutoConfiguration 首页处理:...

mysql延时问题排查
背景介绍 最近遇到一个奇怪的问题,有个业务,每天早上七点半产生主从延时,延时时间12.6K; 期间没有抽数/备份等任务;查看慢日志发现,期间有一个delete任务,在主库执行了161s delete from xxxx_…...
接口设置了responseType:‘blob‘后,接收不到后端错误信息
下载文件流,需要接口设置responseType:blob,接口设置了responseType:blob后,拿不到后端接口的异常信息,我们只需要添加如下代码: const service axios.create({baseURL: ***, // url base url request url// withC…...

无涯教程-Perl - mkdir函数
描述 此功能使用MODE指定的模式创建一个名称和路径EXPR的目录,为清楚起见,应将其作为八进制值提供。 语法 以下是此函数的简单语法- mkdir EXPR,MODE返回值 如果失败,此函数返回0,如果成功,则返回1。 例 以下是显示其基本用法的示例代码- #!/usr/bin/perl -w$dirname &…...

css3 瀑布流布局遇见截断下一列展示后半截现象
css3 瀑布流布局遇见截断下一列展示后半截现象 注:css3实现瀑布流布局简直不要太香~~~~~ 场景-在uniapp项目中 当瀑布流布局column-grap:10px 相邻两列之间的间隙为10px,column-count:2,2列展…...

C++初阶之一篇文章教会你list(理解和使用)
list(理解和使用) 什么是list特点和优势基本操作示例用法与其他序列式容器(如 std::vector 和 std::deque)相比,std::list 显著的区别和优势成员类型 list构造函数1. default (1)2. fill (2)3.range (3)4. copy (4) li…...

如何给Linux开启swap虚拟内存
查看系统内存资源 free -h 创建swap分区 dd if/dev/zero of/swapfile bs1024 count4194304dev/zero:是Linux的一种特殊字符设备(输入设备),可以用来创建一个指定长度用于初始化的空文件,如临时交换文件,该设备无穷尽地提供0&…...

spring按条件注入@Condition及springboot对其的扩展
概述 spring的ioc极大的方便了日常开发,但随着业务的迭代。配置的一些参数在某些情况下需要按条件注入。 比如原先定义的db公共模块下,相关的配置和工具类只是基于mysql的。但是后续有模块需要使用mongo/es等其他数据库,又想继续使用db公共…...

MySQL多表连接查询3
目录 表结构 创建表 表数据 查询需求: 1.查询student表的所有记录 2.查询student表的第2条到4条记录 3.从student表查询所有学生的学号(id)、姓名(name)和院系(department)的信息 4.从s…...

【从零开始学习JAVA | 第四十五篇】反射
目录 前言: 反射: 使用反射的步骤: 1.获取阶段: 2.使用阶段: 反射的应用场景: 使用反射的优缺点: 总结: 前言: Java中的反射是一项强大而灵活的功能࿰…...
顺丰科技数据治理实践
01 顺丰数据治理体系演进路线 顺丰做数据治理十多年,数据治理体系的模块是逐步来建设的。十年前,我们就已经建了数仓,同步做了元数据管理,数据质量管理,以及数据安全的管理。顺丰数据治理的演进路线分 3 个阶段。 第…...

Nginx+Tomcat负载均衡、动静分离实例详细部署
一、反向代理两种模式 四层反向代理 基于四层的iptcp/upd端口的代理 他是http块同一级,一般配置在http块上面。 他是需要用到stream模块的,一般四层里面没有自带,需要编译安装一下。并在stream模块里面添加upstream 服务器名称,…...

Java多线程(3)---锁策略、CAS和JUC
目录 前言 一.锁策略 1.1乐观锁和悲观锁 ⭐ 两者的概念 ⭐实现方法 1.2读写锁 ⭐概念 ⭐实现方法 1.3重量级锁和轻量级锁 1.4自旋锁和挂起等待锁 ⭐概念 ⭐代码实现 1.5公平锁和非公平锁 1.6可重入锁和不可重入锁 二.CAS 2.1为什么需要CAS 2.2CAS是什么 ⭐CAS…...

Linux:Shell编辑之文本处理器(awk)
目录 绪论 1、用法 1.1 格式选项 1.2 awk 常用内置变量 1.3 awk的打印功能 1.4 奇偶打印 1.5 awk运算 1.6 awk的内置函数:getline 1.7 文本过滤打印 1.8 awk条件判断打印 1.9 三元表达式,类似于java 1.10 awk的精确筛选 1.11 awk和tr比较改变…...

探索FSM (有限状态机)应用
有限状态机(FSM) 是计算机科学中的一种数学模型,可用于表示和控制系统的行为。它由一组状态以及定义在这些状态上的转换函数组成。FSM 被广泛用于计算机程序中的状态机制。 有限状态机(FSM)应用场景 在各种自动化系统…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...

五、jmeter脚本参数化
目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...

RabbitMQ 各类交换机
为什么要用交换机? 交换机用来路由消息。如果直发队列,这个消息就被处理消失了,那别的队列也需要这个消息怎么办?那就要用到交换机 交换机类型 1,fanout:广播 特点 广播所有消息:将消息…...

【threejs】每天一个小案例讲解:创建基本的3D场景
代码仓 GitHub - TiffanyHoo/three_practices: Learning three.js together! 可自行clone,无需安装依赖,直接liver-server运行/直接打开chapter01中的html文件 运行效果图 知识要点 核心三要素 场景(Scene) 使用 THREE.Scene(…...