你是否有过以下经历?
- 生活中:
- 页面加载好慢,等待时间太长,退出……
- 页面交互一次,半天无反应,退出……
- 工作中:
- 性能优化方面了解多吗?
- 对公司网站,有没有什么优化的想法💡?
什么是web性能?
MDN上对web性能的定义:
Web 性能是客观的衡量标准,是用户对加载时间和运行时的直观体验。Web 性能指页面加载到可交互和可响应所消耗的时间,以及页面在交互时的流畅度——滚动是否顺滑?按钮能否点击?弹窗能否快速打开,动画是否平滑?Web 性能既包括客观的度量如加载时间,每秒帧数和到页面可交互的时间;也包括用户的对页面内容加载时间的主观感觉。
简单理解: 网站的加载速度快不快,运行效率高不高,用户体验好不好~
为什么要关注web性能?
页面的快速响应有以下几点:
- 提升用户的留存
- 提升转化率
- 良好的体验,减少用户投诉,加速网站的传播
- 等等……
web性能的指标是什么?
为了能衡量用户视觉体验,在以用户为中心的目标,性能指标不断演进。其中,RAIL
是由Google Chrome 团队于 2015 年提出的性能模型, 用于提升浏览器内的用户体验和性能。
响应(Response):
- 目标: 在
100ms
内完成由用户输入启动的转换,让用户感觉交互是即时的。
动画(Animation):
- 目标: 每
10ms
产生一帧。 - 准则: 尽可能利用
100ms
响应预先计算昂贵的工作,以便最大限度地提高达到60 fps
的机会。
fps
(Frames Per Second): 每秒绘制帧数
浏览器空闲时间(Idle):
- 目标: 最大化利用空闲时间以增加页面在
50ms
内响应用户输入的几率。 - 准则: 利用空闲时间完成延期工作。 例如,对于初始页面加载,加载尽可能少的数据,然后使用空闲时间加载其余的数据。
加载(Load):
- 目标: 根据用户的设备和网络能力优化相关的快速加载性能。
- 准则: 目前对于网速快的电脑设备,应该在小于
1s-2s
的时间内加载完成网站,并可以进行用户交互。对于首次加载,在使用速度较慢 3G 连接的中端移动设备上,理想的目标是在5s
或更短的时间内实现可交互。
如何检测web性能
- Google PageSpeed Insights
- WebPageTest
- Lighthouse
- FCP:
首次内容绘制
,浏览器首次绘制来自 DOM 的内容的时间,内容必须是文本
、图片
(包含背景图)、非白色的 canvas 或 SVG
,也包括带有正在加载中的 Web 字体的文本
。- TTI: 表示网页
第一次
完全达到可交互状态 的时间点,浏览器已经可以持续性的响应用户的输入- TBT: 总阻塞时间,度量了
FCP
和TTI
之间的总时间,在该时间范围内,主线程被阻塞足够长的时间(任务在主线程上运行超过50ms)
以防止输入响应。导致用户感觉到延迟,页面缓慢。- CLS: 累计布局偏移,是一种保证页面的视觉稳定性从而提升用户体验的指标方案。
- SI: 速度指数,表示页面可视区域中内容的填充速度的指标。
报告提出的一些建议可行性方向:
-
浏览器开发工具
-
浏览器任务管理器 (点击浏览器右侧3个点 - > 更多工具 - > 任务管理器)
-
network网络分析 (大小,时间 ,时间线->ttfp 等待时间 ,网络加载状态,禁用缓存)
-
perfomance
第一个是记录你的操作的一些性能报告
第二个是发出请求到页面加载的性能报告
-
fps显示每秒帧数计量器 (在浏览器中使用ctrl+shift+p调起面板可搜索)
-
-
Performance API: HTML5新增的API 早期你肯定也用过
console.time()
和console.timeEnd()
来跟踪某一操作的占用时长。这种操作相对来说麻烦且不友好。W3C后面推出了Performance这个API。
直接在控制台输入 window.perforamce.timing
具体字段解释如下:
const timingInfo = window.performance.timing;
// DNS解析,DNS查询耗时
timingInfo.domainLookupEnd - timingInfo.domainLookupStart;
// TCP连接耗时
timingInfo.connectEnd - timingInfo.connectStart;
// 获得首字节耗费时间,也叫TTFB
timingInfo.responseStart - timingInfo.navigationStart;
// domReady时间(与DomContentLoad事件对应)
timingInfo.domContentLoadedEventStart - timingInfo.navigationStart;
// DOM资源下载
timingInfo.responseEnd - timingInfo.responseStart;
// 准备新页面时间耗时
timingInfo.fetchStart - timingInfo.navigationStart;
// 重定向耗时
timingInfo.redirectEnd - timingInfo.redirectStart;
// Appcache 耗时
timingInfo.domainLookupStart - timingInfo.fetchStart;
// unload 前文档耗时
timingInfo.unloadEventEnd - timingInfo.unloadEventStart;
// request请求耗时
timingInfo.responseEnd - timingInfo.requestStart;
// 请求完毕至DOM加载
timingInfo.domInteractive - timingInfo.responseEnd;
// 解释dom树耗时
timingInfo.domComplete - timingInfo.domInteractive;
// 从开始至load总耗时
timingInfo.loadEventEnd - timingInfo.navigationStart;
// 白屏时间
timingInfo.responseStart - timingInfo.fetchStart;
// 首屏时间
timingInfo.domComplete - timingInfo.fetchStart;
- performance monitor
console -> more tools -> performance monitor
性能优化部分实践
-
css资源的处理
-
使用CSS Minifiers
我们可以在webpack中使用 CSSNano或 csso来对我们的CSS代码来进行压缩。
//postcss.config.js module.exports = { plugins: [ require('cssnano')({ preset: 'default', }), ], };
CSSNano
提供了多方面的体积优化能力,例如移除不必要的厂商前缀、对属性进行排序以获得更高的Gzip
压缩比等 -
-
JS文件
-
使用 async 或 defer 属性
推荐使用 async 或 defer 属性标记非关键 JS 文件。
由于 async 或 defer 的执行时机不一致:
通常我们使用 defer 标记需要按照一定顺序执行的脚本,例如业务代码;使用 async 标记一些没有任何依赖的脚本,如埋点、性能统计脚本等.
-
去除重复、无用的js文件
可以通过webpack-bundle-analyzer获取当前项目的分析图。
- 如何降低包的大小
1、使用路由懒加载,分包
2、第三方库按需加载
3、使用compressionWebpackPlugin使用gizp压缩
4、使用组件的异步加载
5、打包的时候取消.map文件
6、使用uglifyJS或者terserWebpackPlugin去压缩js代码
-
-
代码层面
-
防抖节流
-
利用
requestAnimationFrame
代替setTimeOut
实现动画 -
定时器、事件监听等记得卸载。
-