- 工程化优化
- 框架优化
- 网络优化
- 浏览器优化
渲染性能优化
服务端渲染 ssr
- 传统的前后端分离(spa)渲染页面的过程复杂
- ssr渲染页面过程简单,所以性能好
- 如果是纯 h5 页面,ssr是性能优化的终极方案
虚拟列表
- 用户滚动一个长列表时,虚拟列表技术仅渲染当前可见的部分,而不是整个列表。这种方法显著提高了性能,特别是当处理数千甚至数百万条记录时
利用时间切片进行优化
const app = document.querySelector('#app')
const btn: any = document.querySelector('.btn')
btn.onclick = () => {
const add = (index: number) => {
const div: any = document.createElement('div')
div.innerText = index
app.appendChild(div)
}
// 执行 add 三十万次
performChunk(300000, add)
}
// 往requestIdleCallback队列添加异步任务
const scheduler = (task: Function) => {
requestIdleCallback((idle) => {
const hasTime = () => idle.timeRemaining() > 0
task(hasTime)
})
}
// 默认往requestIdleCallback队列添加异步任务
function performChunk(times: number, taskHandler: Function, push=scheduler) {
let i = 0;
function _run() {
if(i >= times) return
push(hasTime => {
while(hasTime() && i < times) {
taskHandler(i)
i++
}
_run()
})
}
_run()
}
图片优化
背景
最近在公司在写微信小程序,该小程序主要展示一些高清图片,所以图片数量非常多,而且图片尺寸也比较大,导致小程序的加载时间非常长。所以这里记录一下如何减少小程序图片的加载时间,优化用户体验。
使用webp格式图片
- 在小程序中是支持
webp格式的图片的,所以我们可以将图片转换为webp格式, webp可以减少图片体积,提升加载速度。- 公司使用的
阿里云oss进行图片存储 - 只需要在图片url后面加一定的参数即可
// 原本图片路径:
let url =' https://.../50403470042.png'
// 转化为webp格式的图片路径:
let url =' https://.../50403470042.png?x-oss-process=image/format,webp'
根据需求设置适当的分辨率
- 阿里云oss支持在图片后面加上参数来设置图片的分辨率,
- 我们可以给图片url后面加上
/resize,w_320即可, - 其中
w_320表示图片宽度为320px。
// 原本图片路径:
let url =' https://.../3%20%282%2.png?x-oss-process=image/format,webp'
// 设置宽度后的图片路径:
let url =' https://.../3%20%282%2.png?x-oss-process=image/format,webp/resize,w_320'
合理使用占位图片
- 如果在网络慢的情况下,image加载图片的过程可能会非常慢,
- 在请求完成之前页面都会因为没有数据而呈现一片空白,这是非常差的用户体验,
- 这里我们可以借助小程序image标签上的
@error和@load事件来实现占位图片的展示。 - 我们可以根据需求去封装一个
LoadImage组件统一处理
<template>
<view class="loadImage-wrapper">
<image v-if="isLoading" :src="defaultImage" :mode="mode" :lazy-load="lazyLoad" />
<image :class="[isLoading ? 'before-load' : '']" :src="imageUrl" :mode="mode" :lazy-load="lazyLoad"
@load="imageLoad" />
</view>
</template>
<script>
export default {
props: {
/**
* 占位图
* @default /static/images/load-image.png
*/
defaultImage: {
type: String,
default: '/static/load-image.png',
},
/**
* 是否使用webp
* @default false
*/
useWebp: {
type: Boolean,
default: false,
},
/**
* 图片的显示模式
* @default scaleToFill
*/
mode: {
type: String,
default: 'scaleToFill',
},
/**
* 图片加载分辨率-宽度
* @default
*/
width: {
type: String,
default: '',
},
/**
* 是否懒加载
* @default true
*/
lazyLoad: {
type: Boolean,
default: true,
},
/**
* 图片地址
* @default
*/
src: {
type: String,
default: '',
},
},
data() {
return {
isLoading: true,
}
},
methods: {
imageLoad() {
this.isLoading = false
},
},
computed: {
imageUrl() {
let url = this.src + '?'
this.useWebp && (url += 'x-oss-process=image/format,webp')
this.width && (url += '/resize,w_' + this.width)
return url
}
},
}
</script>
<style lang="scss" scoped>
.loadImage-wrapper {
.before-load {
width: 0;
height: 0;
opacity: 0;
}
}
</style>
雪碧图
- 针对http1的优化,
对头阻塞 - 雪碧图,也叫
Sprite,是将多个小图片合并成一张大图,然后在页面中使用background-image和background-position属性来显示其中的某一张图片。这样可以减少图片的加载次数,减少图片的大小,同时减少图片的加载时间。在项目中难免会有很多小图标,我们就可以使用雪碧图的方式来使用,减少请求次数。这里我就不做展示了。
CDN
生产环境下我们不会直接用 OSS 的 URL 访问,而是会开启 CDN,用网站域名访问,最终回源到 OSS 服务:


网络性能优化
请求缓存
- 请求缓存是指创建一个带有缓存的请求,
- 当没有命中缓存时发送请求并缓存结果,
- 当有缓存时直接返回缓存。
请求幂等
- 连续调用同一个api接口n次, 只有第一次才发送http请求
- 调用接口后, 查看缓存状态
pendding状态直接发起http请求loading状态- 使用发布订阅模式
- 将 函数 存入数组中
- 当状态变为
success或fail执行数组中的函数
success状态: 直接返回本地缓存fail状态: 重新发送http请求
对头阻塞(针对http1的优化)
- 减少文件数量: 雪碧图
- 增加TCP通道
- 同一个域名最多只能同时加载6个资源
- 使用不同的域名加载资源, 突破6个限制

首页白屏优化&打包体积优化
可通过两个方向进行优化: 代码压缩, 代码分包
代码压缩
- 使用webpack压缩
jscsshtml图片 - 代码复用: 提取公共代码
- treeShaking
- 充分利用webpacke打包机制
treeShaking treeShaking: 就是打包时把没用的代码去掉
- 充分利用webpacke打包机制
// 这样写不好, 会将没使用的组件也打包进去
import UI form 'antd'
// 这样写,如果Button未被使用, Button将被tree shaking 掉
import { Button } from 'antd'
代码分割
- 将不会立马使用的第三方库分包出去
- 将动态导入的代码分包出去:
import('./tool.js') - 等到需要时再加载(懒加载)
- 也可以在空闲时预加载
分页
- 针对列表页
- 默认只展示第一页内容
- 上滑加载更多
延迟加载
- 当首屏有上万dom需要渲染时
- 将首屏页面分层可见部分和不可见部分
- 渲染第1帧加载可见部分
- 渲染第10帧加载不可见部分
const frame = useFrame() // 可通过requestAnimation()实现
return <>
{ frame>1 && <Part1/> }
{ frame>10 && <Part2/> }
{ frame>20 && <Part3/> }
...
</>
懒加载
import('./a.js')
图片懒加载 lazyload
- 针对详情页
- 默认只展示文本内容,然后触发图片懒加载
- 注意:提前设置图片尺寸,尽量只重绘不重排
路由懒加载
- 使用与单页面应用, 不适用于多页面应用
- 路由拆分, 优先保证首页加载
代码懒加载
- 将不会立马使用的第三方库分包出去
- 将动态倒入的代码分包出去:
import('./tool.js') - 等到需要时再加载(懒加载)
预加载
代码预加载
- 将不会立马使用的第三方库分包出去
- 将动态倒入的代码分包出去:
import('./tool.js') - 等到需要时再加载(懒加载)
- 也可以在空闲时预加载
APP预加载
打开页面前提前获取数据 预取
- 如果H5在APP WebView中展示,可使用App预取
- 用户访问列表页时,App预加载文章首屏内容
- 用户进入H5页,直接从APP中获取内容,瞬间展示首屏
Hybrid
- 提前将
htmljscss下载到App内部 - 在App webview中使用file://协议加载页面文件
- 再用Ajax获取内容并展示(也结合App预取)