你是否经历以下场景
- 面试中
- 了解性能优化吗?
- 输入url到看到整个页面经历了什么?
- ……
- 工作中
- 页面加载好慢,不知道是前端问题还是后端问题
- 页面交互卡顿,不知道具体哪里出现了问题
- ……
什么是web性能
简单来说,就是你的网站够不够快,用户体验是不是很好
- 打开速度
- 动画效果
- 表单提交
- 列表滚动
- 页面切换
- ……
MDN上web性能定义:web性能是网站或者应用程序的客观度量和可感知的用户体验
- 减少整体加载时间:减少文件体积、减少http请求、使用预加载
- 使网站尽快可用:仅加载首屏内容、其他内容根据需要进行懒加载
- 平滑和交互性:使用css替代js动画、减少ui重绘
- 感知表现:你的页面可能做得不快,但可以让用户感觉更快,耗时操作要给用户反馈:比如加载动画、进度条、骨架屏等提示信息
- 性能测定:性能指标、性能测试、性能监控持续优化
为什么要关注web性能?
- 用户的留存
- 网站的转化率
- 体验和传播
- 搜索排名
- 用户投诉
- 提升工作绩效
- ……
如何进行web性能优化?
- 首先需要了解性能指标-多快才算快?
- 使用专业的工具可量化地评估出网站或应用的性能表现
- 然后立足于网站页面响应的生命周期(浏览器输入地址栏),分析出造成较差性能表现的原因
- 最后进行技术改造、可行性分析等具体的优化实施
- 迭代优化
性能指标
- webpageTest
- NetWork网络分析
1. F12 network进行调试,以淘宝为例
可以查看具体的加载时间等信息
2. 此外还有一个瀑布流的概念 waterfall
按瀑布的形式,从上而下展示各个资源请求的顺序和消耗的时间
点击在瀑布上可以查看具体的内容
queueing请求排队的时间
DNS Lookup:DNS查找的过程时间
initial connection请求与服务器连接的时间(TCP)
SSL:https 证书验证的时间
request sent 发送请求的时间
waiting(TTFB) 等待响应的时间 这个指标是最重要的,用户最直观的感受 影响因素:后台的处理能力、回路网络的情况,会不会有延迟
content download 下载资源的时间(不能过长)
3. 蓝线和红线
蓝线:dom加载完成的时间
红线:所有资源加载完成的时间
4. 保存当前网页指标,方便以后对比
5. 查看动画帧数
找到 show frames per second(FPS)meter
点击
Frames 74% 这个指标越高越好 一般要大于60fps
6. 异步请求的指标
按理说 异步请求在1s内返回,都是可以的,我们可以进行压缩处理,实在不行我们可以进行loading过渡
7.RAIL测量模型
1.R\A\I\L含义
R:response 响应
A:animation 动画
I:idle 空闲
L:load加载
2.RAIL评估标准指标
response响应:处理事件应在50ms以内完成
在用户输入到收到响应,我们要在100ms内完成,但是浏览器需要对事件进行处理(预留50ms)所以我们能处理事件的时候最多为50ms
animation动画:每10ms产生一帧
idle空闲:足够多,这样用户交互来的时候,我们有足够的时间进行处理
load加载:在5s内完成内容加载并可以交互
8.性能测量工具
1. 我们常用的 Chrome DevTools
我们调到performance那一栏
会提示
第一个是记录你的操作的一些性能报告
第二个是发出请求到页面加载的性能报告
2. lighthouse的使用
1.全局:npm install -g lighthouse
2.lighthouse 网站地址
3.会生成一个测试报告,代表运行成功
4.我们可以按照地址直接打开报告
erformance 性能 SEO搜索引擎
我们主要研究performance
根据上图会发现,是个分屏有七个都是白的,说明渐进式加载做的不是很好
lighthouse最好的好处是 会给你提出很多建议,和预计会减少的时间
比如说建议第一个,会告诉你移除未被使用的js,并给你指出具体的js是什么
还有就是建议第二个是减少渲染阻塞的资源
其他的先不说了,之后会提到
性能测量
如果把对网站的性能优化比作一场旅行,它无疑是漫长且可能还略带泥泞的,那么开始之前我们有必要对网站进行性能测量,为了知道优化的方向在何处。通常我们会借助一些工具来性能测量,下面会介绍两个操作
- 浏览器DevTools调试工具
- 网络监控分析
- 性能监控分析
- 灯塔(lighthouse)
- 网站整体质量评估,并给出优化建议
- WebPageTest
- 多测试地点
- 全面的性能报告
- ……
生命周期
网站的生命周期,通俗的讲就是:从我们在浏览器地址栏输入一个URL后,到整个页面渲染出来的过程。整个过程包括域名解析、建立TCP连接、然后通过HTTP进行会话、压缩与解压缩、以及前端的关键渲染路径等。把这些阶段拆解来看,不仅能容易的获得优化性能的启发,也能构建完整的前端知识框架。网站页面加载的生命周期如下图所示
优化方案
- 从发出请求到收到响应的优化,比如DNS查询、HTTP长连接、HTTP2\HTTP压缩、HTTP缓存等
- 关键渲染路径优化,比如是否存在不必要的重绘和回流等
- 加载过程的优化,比如延迟加载,是否有不需要在首屏展示的非关键信息,占用了页面加载的时间
- 资源优化,比如图片、视频等不同格式类型会有不同的适用场景,在使用的过程中是否不恰当
- 构建优化,比如压缩合并、基于webpack构建优化方案等
- ……
谷歌工具的使用
consle→ more tools → performance monitor
性能指标参数
FCP(First Contentful Paint) 首次内容绘制
浏览器首次绘制来自DOM的内容的时间,内容必须是文本、图片(包含背景图)、非白色的canvas或SVG,包括带有正在加载中的web字体的文本
LCP(Largest Contentful Paint) 最大内容绘制
可视区域中最大的内容元素呈现到屏幕上的时间,用以估算页面的主要内容对用户可见时间(2.5s)
FID(First Input Delay) 首次输入延迟
从用户第一次与页面交互到浏览器能够响应交互的时间
输入延迟是引入浏览器忙于解析和执行应用程序加载的大量计算JavaScript。
第一次输入延迟通常发生在第一次内容绘制(FCP)和可持续交互时间(TTI)之间,这时页面已经呈现了一些内容,但还不能进行可靠地交互
浏览器接收到用户输入操作时,主线程正在忙于执行一个耗时比较长的任务,只有当这个任务执行完成后,浏览器才能响应用户的输入操作,它必须等待的时间===该用户的FID值。
例如,以下所有的HTML元素都需要在响应用户交互之间等待主线程上正在进行的任务完成:
文本输入框,复选框和单选按钮、 选择下拉菜单 链接
TTI(Time to Interactive) 可持续交互时间
网页第一次完全达到可交互状态的时间点,浏览器可以持续性地响应用户的输入。完全达到可交互状态的时间点是在最后一个长任务完成的时间,并在随后的5s内网络和主线程是空闲的
TBT(Total Block Time) 总阻塞时间
度量了FCP和TTI之间的总时间,在该时间范围内,主线程被阻塞足够长的时间以防止输入响应。我们说主线程“被阻止”是因为浏览器无法中断正在进行的任务,如果用户在较长的任务中间与页面进行交互,则浏览器必须等待任务完成才能响应。给定的长任务的阻止时间是其持续时间超过50ms,页面的总阻塞时间=FCP+TTI之间发生的每个长任务的阻塞时间的总和
上面时间轴有5个任务,其中有3个持续时间超过50ms的长任务,下图显示了每个长任务的阻塞时间
因此,虽然在主线程上运行任务话花费总时间为560ms,但只有345ms被视为阻塞时间
CLS(Cumulative Layout Shift) 累计布局偏移
CLS会测量在页面整个生命周期中发生的每个意外的布局移位的所有单独布局移位分数的总和,它是一种保证页面的视觉稳定性,从而提高用户体验的指标方案。
Speed Index 速度指数
页面可视区域中内容的填充速度的指标,可以通过计算页面可见区域内容显示的平均时间来衡量
性能优化
渲染优化
-
浏览器渲染流程
初次渲染—浏览器渲染流程
二次渲染主要是这五个步骤:
JavaScript:指的是用js可以实现页面上的视觉变化,比如动画等;除此之外我们还可以用css做动画过渡等,这里只是统一代表,改变页面视觉变化的一系列操作
Style:浏览器对样式就行重新的计算,选择器重新的匹配,计算那些css收到了影响,新的规则是什么样的。这样每个元素是什么样子就清楚了
Layout:布局,把元素按照说的样式绘制到页面上,我们需要知道大小和位置
Paint:绘制,把元素绘制到页面上,画文字图片阴影等
Composite:复合,按照图层绘制,最后把各个图层绘制的合成在一起,类似于ps那种感觉
-
布局和绘制的优化
布局,绘制很耗资源,我们可以尽量避免这两个阶段进行优化影响回流的操作
第一次叫做布局,当修改一些内容再布局,我们称为回流,其实和布局本质是一样的
①添加/删除元素②display:none③移动元素位置④操作style⑤读取offsetLeft,scrollTop,clientWidth⑥修改浏览器大小、字体大小
-
requestanimationframe 这个API(见代码DEMO)
相当一部分的浏览器的显示频率是`16.7ms,显示器16.7ms刷新间隔之前发生了其他绘制请求(setTimeout),导致所有第三帧丢失,继而导致动画断续显示(堵车的感觉),这就是过度绘制带来的问题。不仅如此,这种计时器频率的降低也会对电池使用寿命造成负面影响,并会降低其他应用的性能。这也是为何setTimeout的定时器值推荐最小使用16.7ms的原因(16.7 = 1000 / 60, 即每秒60帧)
而requestAnimationFrame就是为了这个而出现的。所做的事情很简单,跟着浏览器的绘制走,如果浏览设备绘制间隔是16.7ms,那我就这个间隔绘制;如果浏览设备绘制间隔是10ms, 我就10ms绘制。这样就不会存在过度绘制的问题,动画不会掉帧。
requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果
requestAnimationFrame(callback) 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
requestAnimationFrame(callback):优势:由系统决定回调函数的执行时机。60Hz的刷新频率,那么每次刷新的间隔中会执行一次回调函数,不会引起丢帧,不会卡顿。让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果
代码优化
- 减少iframe使用
- 压缩空白符
- 避免节点深层级嵌套
- 避免table布局(开销大,维护麻烦)
- 删除注释
- CSS&JS尽量外链(导致html过大,不好优化)CSS放在头部 JS放在body底部
- 删除元素默认属性
- 定时器的及时清除&关闭弹窗&离开页面数据的清空
- font-display:字体更快的出现
该属性有五个值:auto block swap fallback optional
auto用浏览器自动进行选择,没有太大用处 根据上图可知: block(阻塞):3s等待,在前3s不显示,如果3s之后期望字体下载完了,就用下载好的期望字体,要是3s之后期望字体还没有下载完,就用默认字体,什么时候期望字体下载完了,在进行替换
swap(交换):刚开始加载就用默认字体,什么时候期望字体下载完成,在对默认字体进行替换
fallback:其实是对block的一种优化,等待时间变为100ms,等待时间之后若期望字体下载完了,用期望字体,否则用默认字体,什么时候期望字体下载完什么时候进行替换
optional:手机端特别优化的,等待时间100ms,若100ms 期望字体下载完了就一直用期望字体,若没下载完就一直用默认字体,永不替换
资源优化
HTML压缩
- 使用在线工具进行压缩
- 使用html-minifier等npm工具(webpack)
图片压缩
图片懒加载
原理:一张图片就是一个img标签,浏览器是否发起请求图片是根据img的src属性,所以实现懒加载的关键就是,在图片没有进入可视区域时,先不给img的src赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给src赋值
CSS压缩
JS压缩和混淆
今天的分享就到这里了,这里只是抛砖引玉,想引起大家在开发者对性能提升的意识,这也是中高级前端入门必备;有观点不当之处欢迎交流~