Files
dabai_web_f/docs/性能优化清单.md
2026-03-17 14:52:07 +08:00

532 lines
9.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 性能优化清单
## 一、首屏加载优化
### 1.1 代码分割
```javascript
// 路由懒加载
const UserProfile = () => import('@/pages/user/profile')
// 组件懒加载
components: {
HeavyComponent: () => import('@/components/HeavyComponent.vue')
}
```
### 1.2 小程序分包加载
```json
{
"subPackages": [
{
"root": "subPackages/order",
"pages": ["list/index", "detail/index"]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["subPackages/order"]
}
}
}
```
### 1.3 资源预加载
```javascript
// 预加载关键资源
onLoad() {
// 预加载下一页数据
this.preloadNextPage()
// 预加载图片
uni.preloadImage({
src: '/static/images/banner.jpg'
})
}
```
### 1.4 骨架屏
```vue
<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 虚拟列表
对于长列表使用虚拟滚动:
```vue
<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 图片懒加载
```vue
<template>
<!-- 小程序端 -->
<image
:src="imageSrc"
lazy-load
mode="aspectFill"
/>
<!-- H5端使用 Intersection Observer -->
<img
v-lazy="imageSrc"
@load="handleImageLoad"
/>
</template>
```
### 2.3 防抖与节流
```javascript
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 条件渲染优化
```vue
<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 请求合并
```javascript
// 合并多个接口请求
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 请求缓存
```javascript
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 请求重试
```javascript
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 请求取消
```javascript
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 及时清理
```javascript
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 大数据处理
```javascript
// 分批处理大数据
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 使用
```javascript
// 使用 WeakMap 避免内存泄漏
const cache = new WeakMap()
function cacheData(obj, data) {
cache.set(obj, data)
}
function getCachedData(obj) {
return cache.get(obj)
}
```
## 五、图片优化
### 5.1 图片压缩
```javascript
// 上传前压缩图片
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 响应式图片
```vue
<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 图片预加载
```javascript
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 优化
```javascript
// 避免频繁 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 自定义组件
```javascript
// 使用自定义组件代替模板
Component({
options: {
// 启用纯数据字段
pureDataPattern: /^_/,
// 启用多slot支持
multipleSlots: true
},
properties: {
title: String
},
data: {
_privateData: 'private' // 纯数据字段,不参与渲染
}
})
```
### 6.3 分包预下载
```json
{
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["subPackages/order"]
}
}
}
```
## 七、H5 特定优化
### 7.1 PWA 支持
```javascript
// 注册 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 加速
```javascript
// 静态资源使用 CDN
const CDN_URL = 'https://cdn.example.com'
export const getStaticUrl = (path) => {
return `${CDN_URL}${path}`
}
```
### 7.3 Gzip 压缩
```javascript
// vite.config.js
import viteCompression from 'vite-plugin-compression'
export default {
plugins: [
viteCompression({
algorithm: 'gzip',
ext: '.gz'
})
]
}
```
## 八、性能监控
### 8.1 性能指标收集
```javascript
// 页面加载时间
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 性能上报
```javascript
function reportPerformance(data) {
// 上报到监控平台
uni.request({
url: 'https://monitor.example.com/report',
method: 'POST',
data: {
type: 'performance',
...data
}
})
}
```
## 九、优化检查清单
- [ ] 启用代码分割和懒加载
- [ ] 实现图片懒加载
- [ ] 使用虚拟列表处理长列表
- [ ] 添加请求缓存机制
- [ ] 实现请求重试机制
- [ ] 合并并发请求
- [ ] 压缩图片资源
- [ ] 使用 CDN 加速静态资源
- [ ] 启用 Gzip 压缩
- [ ] 小程序分包加载
- [ ] 优化 setData 调用
- [ ] 及时清理定时器和监听器
- [ ] 使用防抖和节流
- [ ] 添加骨架屏
- [ ] 实现性能监控