https://juejin.cn/post/6949896020788690958#heading-60
什么是新能优化
简而言之就是让用户感觉这个网站很「快」(至少不慢hh),这里的「快」有两种,一种是「真的快」一种是「觉得快」
- 「真的快」:可以客观衡量的指标,像网页访问时间、交互响应时间、跳转页面时间
- 「觉得快」:用户主观感知的性能,通过视觉引导等手段转移用户对等待时间的关注 做好这两方面都能提升用户对网站的性能评价。
权衡取舍
一种优化方案可能适用于大多数项目,但是某些特殊情况下很可能会起反效果。
举个🌰,由于浏览器有单域名下并发请求限制,通常我们会将依赖统一打成一个vendor包(vue-cli默认策略),减少首屏请求数,且依赖不变动的情况下文件指纹不变,可以有效利用304缓存。在依赖不多的情况这么处理确实有助于提升加载速度,但一旦依赖多起来,vendor就会特别的大,在弱网条件下,会严重拖慢页面显示。这显然不是我们想要的,所以我们根据情况会对vendor进行拆分,比如拆分到CDN,或者直接拆分到页面中
Rail 模型
Google 为前端页面性能的评估提出了 RAIL 模型,核心内容如下:
- Response 响应
- Animation 动画
- Idle 空闲
- Load 加载
常规性能指标
性能指标其实有不少的内容,但在这我们指列举比较常用的几种:
- 首次绘制(First Paint,FP)
- 在渲染进程确认要渲染当前响应资源后,渲染进程会先创建一个空白页面,通常把创建空白页面的这个时间点称为 First Paint,简称 FP
- 所谓的 白屏时间 其实指的就是创建这个空白页面到浏览器开始渲染非空白内容的时间,比如页面背景发生变化等
- 首次内容绘制(First Contentful Paint,FCP)
- 当用户看见一些 “内容” 元素被绘制在页面上的时间点,和白屏是不一样,它可以是 文本 首次绘制,或 SVG 首次出现,或 Canvas 首次绘制等,即当页面中绘制了第一个 像素 时,这个时间点称为 First Content Paint,简称 FCP
- 首屏时间 / 最大内容绘制(Largest Contentful Paint, LCP)
- LCP 是一种新的性能度量标准,LCP 侧重于用户体验的性能度量标准,与现有度量标准相比,更容易理解与推理,当首屏内容完全绘制完成时,这个时间点称为 Largest Content Paint,简称 LCP
- 最大内容绘制应在 2.5s 内完成
- 首次输入延迟(First Input Delay, FID)
- FID 测量的是当用户第一次在页面上交互的时候(点击链接、点击按钮 或 自定义基于 js 的事件),到浏览器实际开始处理这个事件的时间
- 首次输入延迟应在 100ms 内完成
- 累积布局偏移(Cumulative Layout Shift, CLS)
- CLS 是为了测量 视觉稳定性,以便提供良好的用户体验
- 累积布局偏移应保持在 0.1 或更少
- 首字节达到时间(Time to First Byte,TTFB)
- 指的是浏览器开始收到服务器响应数据的时间(后台处理时间 + 重定向时间),是反映服务端响应速度的重要指标
- TTFB 时间如果超过 500ms,用户在打开网页的时就会感觉到明显的等待
优化方案
(一)感知优化
1.1 白屏时的loading动画
首屏优化,在JS没解析执行前,让用户能看到Loading动画,减轻等待焦虑。通常会在index.html上写简单的CSS动画,直到Vue挂载后替换挂载节点的内容,但这种做法实测也会出现短暂的白屏,建议手动控制CSS动画关闭
1.2 首屏骨架加载
骨架屏可以理解为是当数据还未加载进来前,页面的一个空白版本,一个简单的关键渲染路径。用户会看到一个样式简单,描绘了当前页面的大致框架的骨架屏页面,然后骨架屏中各个占位部分被实际资源完全替换,这个过程中用户会觉得内容正在逐渐加载即将呈现,降低了用户的焦躁情绪,使得加载过程主观上变得流畅。
饿了么开源骨架屏方案
在 vue 中使用 ```javascript const { SkeletonPlugin } = require(‘page-skeleton-webpack-plugin’) const path = require(‘path’)npm install --save-dev page-skeleton-webpack-plugin
module.exports = {
configureWebpack: {
plugins: [
new SkeletonPlugin({
pathname: path.resolve(dirname, ‘./shell’), // 用来存储 shell 文件的地址
staticDir: path.resolve(dirname, ‘./dist’), // 最好和 output.path
相同
routes: [‘/‘], // 将需要生成骨架屏的路由添加到数组中
excludes: [‘.van-nav-bar’, ‘.van-tabbar’] // 需要忽略的css选择器
})
],
},
chainWebpack: (config) => { // 解决vue-cli3脚手架创建的项目压缩html 干掉导致骨架屏不生效
if (process.env.NODE_ENV !== ‘development’) {
config.plugin(‘html’).tap(opts => {
opts[0].minify.removeComments = false
return opts
})
}
},
};
```
骨架屏实现思路
一般首页我们采用自定义组件的方式去实践,其他页面使用 UI 提供的 SVG 图片