9.6 KiB
9.6 KiB
性能优化清单
一、首屏加载优化
1.1 代码分割
// 路由懒加载
const UserProfile = () => import('@/pages/user/profile')
// 组件懒加载
components: {
HeavyComponent: () => import('@/components/HeavyComponent.vue')
}
1.2 小程序分包加载
{
"subPackages": [
{
"root": "subPackages/order",
"pages": ["list/index", "detail/index"]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["subPackages/order"]
}
}
}
1.3 资源预加载
// 预加载关键资源
onLoad() {
// 预加载下一页数据
this.preloadNextPage()
// 预加载图片
uni.preloadImage({
src: '/static/images/banner.jpg'
})
}
1.4 骨架屏
<template>
<view v-if="loading" class="skeleton">
<view class="skeleton-avatar" />
<view class="skeleton-line" />
<view class="skeleton-line" />
</view>
<view v-else class="content">
<!-- 实际内容 -->
</view>
</template>
二、渲染性能优化
2.1 虚拟列表
对于长列表使用虚拟滚动:
<template>
<recycle-list
:list="dataList"
:item-height="100"
>
<template v-slot="{ item }">
<view class="list-item">
{{ item.title }}
</view>
</template>
</recycle-list>
</template>
2.2 图片懒加载
<template>
<!-- 小程序端 -->
<image
:src="imageSrc"
lazy-load
mode="aspectFill"
/>
<!-- H5端使用 Intersection Observer -->
<img
v-lazy="imageSrc"
@load="handleImageLoad"
/>
</template>
2.3 防抖与节流
import { debounce, throttle } from '@/utils/performance'
export default {
methods: {
// 搜索输入防抖
handleSearch: debounce(function(keyword) {
this.search(keyword)
}, 300),
// 滚动事件节流
handleScroll: throttle(function(e) {
this.updateScrollPosition(e)
}, 100)
}
}
2.4 条件渲染优化
<template>
<!-- 使用 v-show 代替 v-if(频繁切换) -->
<view v-show="isVisible">内容</view>
<!-- 使用 v-if 代替 v-show(不常切换) -->
<view v-if="hasPermission">内容</view>
<!-- 使用 v-once 渲染静态内容 -->
<view v-once>{{ staticContent }}</view>
</template>
三、网络请求优化
3.1 请求合并
// 合并多个接口请求
async loadPageData() {
const [bannerData, menuData, contentData] = await Promise.all([
api.getBanner(),
api.getMenu(),
api.getContent()
])
this.bannerList = bannerData
this.menuList = menuData
this.contentList = contentData
}
3.2 请求缓存
class RequestCache {
constructor() {
this.cache = new Map()
this.cacheTime = 5 * 60 * 1000 // 5分钟
}
get(key) {
const item = this.cache.get(key)
if (!item) return null
if (Date.now() - item.timestamp > this.cacheTime) {
this.cache.delete(key)
return null
}
return item.data
}
set(key, data) {
this.cache.set(key, {
data,
timestamp: Date.now()
})
}
}
// 使用缓存
const cache = new RequestCache()
export const getUserInfo = async (userId) => {
const cacheKey = `user_${userId}`
const cached = cache.get(cacheKey)
if (cached) return cached
const data = await request.get(`/user/${userId}`)
cache.set(cacheKey, data)
return data
}
3.3 请求重试
async function requestWithRetry(config, retryCount = 0) {
try {
return await request(config)
} catch (error) {
if (retryCount < 3) {
await new Promise(resolve => setTimeout(resolve, 1000))
return requestWithRetry(config, retryCount + 1)
}
throw error
}
}
3.4 请求取消
class RequestManager {
constructor() {
this.pendingRequests = new Map()
}
addRequest(key, requestTask) {
// 取消之前的相同请求
if (this.pendingRequests.has(key)) {
this.pendingRequests.get(key).abort()
}
this.pendingRequests.set(key, requestTask)
}
removeRequest(key) {
this.pendingRequests.delete(key)
}
cancelAll() {
this.pendingRequests.forEach(task => task.abort())
this.pendingRequests.clear()
}
}
四、内存优化
4.1 及时清理
export default {
data() {
return {
timer: null,
observer: null
}
},
beforeUnmount() {
// 清理定时器
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
// 清理观察器
if (this.observer) {
this.observer.disconnect()
this.observer = null
}
// 清理事件监听
uni.offNetworkStatusChange()
}
}
4.2 大数据处理
// 分批处理大数据
function processBigData(data, batchSize = 100) {
const batches = []
for (let i = 0; i < data.length; i += batchSize) {
batches.push(data.slice(i, i + batchSize))
}
return batches.reduce((promise, batch) => {
return promise.then(() => {
return new Promise(resolve => {
setTimeout(() => {
processBatch(batch)
resolve()
}, 0)
})
})
}, Promise.resolve())
}
4.3 WeakMap 使用
// 使用 WeakMap 避免内存泄漏
const cache = new WeakMap()
function cacheData(obj, data) {
cache.set(obj, data)
}
function getCachedData(obj) {
return cache.get(obj)
}
五、图片优化
5.1 图片压缩
// 上传前压缩图片
function compressImage(filePath) {
return new Promise((resolve, reject) => {
uni.compressImage({
src: filePath,
quality: 80,
success: (res) => resolve(res.tempFilePath),
fail: reject
})
})
}
5.2 图片格式选择
- 照片:使用 JPEG 格式
- 图标:使用 PNG 或 SVG 格式
- 动画:使用 GIF 或 WebP 格式
- 透明背景:使用 PNG 格式
5.3 响应式图片
<template>
<image
:src="getImageUrl()"
mode="aspectFill"
/>
</template>
<script>
export default {
methods: {
getImageUrl() {
const systemInfo = uni.getSystemInfoSync()
const dpr = systemInfo.pixelRatio
// 根据设备像素比选择图片
if (dpr >= 3) {
return this.image + '@3x.jpg'
} else if (dpr >= 2) {
return this.image + '@2x.jpg'
}
return this.image + '.jpg'
}
}
}
</script>
5.4 图片预加载
function preloadImages(urls) {
return Promise.all(
urls.map(url => {
return new Promise((resolve, reject) => {
uni.getImageInfo({
src: url,
success: resolve,
fail: reject
})
})
})
)
}
六、小程序特定优化
6.1 setData 优化
// 避免频繁 setData
let updateTimer = null
let pendingData = {}
function batchUpdate(data) {
Object.assign(pendingData, data)
if (updateTimer) return
updateTimer = setTimeout(() => {
this.setData(pendingData)
pendingData = {}
updateTimer = null
}, 16) // 约60fps
}
// 避免 setData 传递大数据
// 不好的做法
this.setData({
list: this.data.list.concat(newList)
})
// 好的做法
this.setData({
[`list[${this.data.list.length}]`]: newItem
})
6.2 自定义组件
// 使用自定义组件代替模板
Component({
options: {
// 启用纯数据字段
pureDataPattern: /^_/,
// 启用多slot支持
multipleSlots: true
},
properties: {
title: String
},
data: {
_privateData: 'private' // 纯数据字段,不参与渲染
}
})
6.3 分包预下载
{
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["subPackages/order"]
}
}
}
七、H5 特定优化
7.1 PWA 支持
// 注册 Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
}
// sw.js
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll([
'/',
'/static/css/main.css',
'/static/js/main.js'
])
})
)
})
7.2 CDN 加速
// 静态资源使用 CDN
const CDN_URL = 'https://cdn.example.com'
export const getStaticUrl = (path) => {
return `${CDN_URL}${path}`
}
7.3 Gzip 压缩
// vite.config.js
import viteCompression from 'vite-plugin-compression'
export default {
plugins: [
viteCompression({
algorithm: 'gzip',
ext: '.gz'
})
]
}
八、性能监控
8.1 性能指标收集
// 页面加载时间
const pageLoadTime = performance.timing.loadEventEnd - performance.timing.navigationStart
// 首屏渲染时间
const firstPaintTime = performance.getEntriesByType('paint')[0].startTime
// 接口请求时间
const apiTime = performance.getEntriesByType('resource')
.filter(item => item.initiatorType === 'xmlhttprequest')
8.2 性能上报
function reportPerformance(data) {
// 上报到监控平台
uni.request({
url: 'https://monitor.example.com/report',
method: 'POST',
data: {
type: 'performance',
...data
}
})
}
九、优化检查清单
- 启用代码分割和懒加载
- 实现图片懒加载
- 使用虚拟列表处理长列表
- 添加请求缓存机制
- 实现请求重试机制
- 合并并发请求
- 压缩图片资源
- 使用 CDN 加速静态资源
- 启用 Gzip 压缩
- 小程序分包加载
- 优化 setData 调用
- 及时清理定时器和监听器
- 使用防抖和节流
- 添加骨架屏
- 实现性能监控