uni-app 网络优化
核心知识点
1. 网络请求优化
网络请求是应用与服务器交互的重要环节,优化网络请求可以显著提升应用性能和用户体验。
1.1 请求合并与批量处理
- 合并多个请求:将多个小请求合并为一个大请求,减少网络连接次数
- 批量处理数据:对于需要多次请求的数据,采用批量获取的方式
- 使用 GraphQL:如果后端支持,使用 GraphQL 减少冗余数据传输
1.2 请求时机优化
- 预加载:在用户可能需要数据之前提前加载
- 懒加载:仅在需要时才加载数据
- 合理设置请求时机:避免在页面初始化时同时发送过多请求
1.3 请求参数优化
- 减少请求参数大小:只传递必要的参数
- 使用 POST 而非 GET:对于大数据量的请求,使用 POST 方法
- 压缩请求数据:对较大的请求数据进行压缩
2. 数据压缩与传输优化
2.1 响应数据压缩
- 启用 GZIP 压缩:确保服务器启用 GZIP 压缩
- 选择合适的数据格式:JSON 通常比 XML 更紧凑
- 使用 Protocol Buffers:对于性能要求高的场景,考虑使用 Protocol Buffers
2.2 数据传输优化
- 使用 HTTPS:虽然 HTTPS 有一定的性能开销,但提供了安全保障
- 启用 HTTP/2:利用 HTTP/2 的多路复用特性
- 避免重定向:减少 301/302 重定向
- 使用 CDN:对于静态资源,使用 CDN 加速
3. 缓存策略
3.1 HTTP 缓存
- 合理设置 Cache-Control 头:利用浏览器缓存
- 使用 ETag 和 Last-Modified:实现高效的缓存验证
- 设置适当的缓存过期时间:根据数据更新频率设置
3.2 本地缓存
- 使用 uni.setStorageSync/uni.setStorage:缓存不常变化的数据
- 实现多级缓存:内存缓存 + 本地存储缓存
- 缓存策略选择:根据数据类型选择合适的缓存策略
3.3 离线缓存
- 实现 Service Worker:在 Web 端启用离线缓存
- 预缓存关键资源:确保核心功能在离线时也能使用
- 数据同步策略:实现离线数据的同步机制
4. 网络错误处理与重试机制
- 合理的错误处理:对网络错误进行友好的提示
- 智能重试策略:对临时性错误进行有限次数的重试
- 降级方案:当网络不可用时,提供合理的降级方案
- 网络状态监测:监测网络状态变化,及时调整应用行为
实用案例分析
案例一:实现请求拦截器和响应拦截器
问题描述
在应用中,每个网络请求都需要添加认证信息、处理错误等重复逻辑,导致代码冗余。
解决方案
使用请求拦截器和响应拦截器统一处理请求前和响应后的逻辑。
代码示例
// api/request.js
class Request {
constructor() {
this.baseURL = 'https://api.example.com';
this.timeout = 10000;
this.retryCount = 3;
}
// 请求拦截器
requestInterceptor(config) {
// 添加认证token
const token = uni.getStorageSync('token');
if (token) {
config.header = {
...config.header,
'Authorization': `Bearer ${token}`
};
}
// 添加时间戳,避免缓存
if (config.method === 'GET') {
config.url = `${config.url}${config.url.includes('?') ? '&' : '?'}t=${Date.now()}`;
}
return config;
}
// 响应拦截器
responseInterceptor(response) {
if (response.statusCode === 200) {
return response.data;
} else {
this.handleError(response);
return Promise.reject(response);
}
}
// 错误处理
handleError(response) {
switch (response.statusCode) {
case 401:
uni.showToast({ title: '未授权,请重新登录', icon: 'none' });
// 跳转到登录页
uni.navigateTo({ url: '/pages/login/login' });
break;
case 403:
uni.showToast({ title: '拒绝访问', icon: 'none' });
break;
case 404:
uni.showToast({ title: '请求地址不存在', icon: 'none' });
break;
case 500:
uni.showToast({ title: '服务器内部错误', icon: 'none' });
break;
default:
uni.showToast({ title: `请求失败:${response.statusCode}`, icon: 'none' });
}
}
// 发送请求
async request(options) {
const config = this.requestInterceptor({
baseURL: this.baseURL,
timeout: this.timeout,
...options
});
let retry = 0;
while (retry < this.retryCount) {
try {
const response = await uni.request(config);
return this.responseInterceptor(response[1]);
} catch (error) {
retry++;
if (retry >= this.retryCount) {
uni.showToast({ title: '网络请求失败,请检查网络连接', icon: 'none' });
return Promise.reject(error);
}
// 延迟重试
await new Promise(resolve => setTimeout(resolve, 1000 * retry));
}
}
}
// 快捷方法
get(url, data, config = {}) {
return this.request({
method: 'GET',
url,
data,
...config
});
}
post(url, data, config = {}) {
return this.request({
method: 'POST',
url,
data,
...config
});
}
put(url, data, config = {}) {
return this.request({
method: 'PUT',
url,
data,
...config
});
}
delete(url, data, config = {}) {
return this.request({
method: 'DELETE',
url,
data,
...config
});
}
}
export default new Request();案例二:实现多级缓存策略
问题描述
应用中频繁请求相同的数据,导致网络请求过多,影响性能。
解决方案
实现多级缓存策略,包括内存缓存和本地存储缓存,减少重复的网络请求。
代码示例
// utils/cache.js
class CacheManager {
constructor() {
this.memoryCache = new Map();
this.memoryCacheExpire = new Map();
}
// 设置缓存
set(key, value, expire = 3600000) { // 默认缓存1小时
// 设置内存缓存
this.memoryCache.set(key, value);
this.memoryCacheExpire.set(key, Date.now() + expire);
// 设置本地存储缓存
try {
uni.setStorageSync(key, {
value,
expire: Date.now() + expire
});
} catch (e) {
console.error('设置本地缓存失败:', e);
}
}
// 获取缓存
get(key) {
// 先从内存缓存获取
if (this.memoryCache.has(key)) {
const expire = this.memoryCacheExpire.get(key);
if (Date.now() < expire) {
return this.memoryCache.get(key);
} else {
// 内存缓存过期,清除
this.memoryCache.delete(key);
this.memoryCacheExpire.delete(key);
}
}
// 从本地存储获取
try {
const cache = uni.getStorageSync(key);
if (cache && Date.now() < cache.expire) {
// 更新内存缓存
this.memoryCache.set(key, cache.value);
this.memoryCacheExpire.set(key, cache.expire);
return cache.value;
} else {
// 本地缓存过期,清除
uni.removeStorageSync(key);
}
} catch (e) {
console.error('获取本地缓存失败:', e);
}
return null;
}
// 删除缓存
remove(key) {
this.memoryCache.delete(key);
this.memoryCacheExpire.delete(key);
try {
uni.removeStorageSync(key);
} catch (e) {
console.error('删除本地缓存失败:', e);
}
}
// 清除所有缓存
clear() {
this.memoryCache.clear();
this.memoryCacheExpire.clear();
try {
uni.clearStorageSync();
} catch (e) {
console.error('清除本地缓存失败:', e);
}
}
}
export default new CacheManager();使用示例
import request from '@/api/request';
import cache from '@/utils/cache';
// 获取用户信息
export const getUserInfo = async () => {
const cacheKey = 'userInfo';
// 先尝试从缓存获取
const cachedData = cache.get(cacheKey);
if (cachedData) {
return cachedData;
}
// 缓存不存在,从服务器获取
const data = await request.get('/user/info');
// 设置缓存,缓存10分钟
cache.set(cacheKey, data, 10 * 60 * 1000);
return data;
};
// 获取商品列表
export const getGoodsList = async (params) => {
const cacheKey = `goodsList_${JSON.stringify(params)}`;
// 先尝试从缓存获取
const cachedData = cache.get(cacheKey);
if (cachedData) {
return cachedData;
}
// 缓存不存在,从服务器获取
const data = await request.get('/goods/list', params);
// 设置缓存,缓存5分钟
cache.set(cacheKey, data, 5 * 60 * 1000);
return data;
};案例三:实现图片懒加载
问题描述
页面中存在大量图片,一次性加载所有图片会导致页面加载缓慢,消耗过多流量。
解决方案
实现图片懒加载,仅在图片进入视口时才加载。
代码示例
<template>
<view class="lazy-load-demo">
<view class="image-item" v-for="(item, index) in images" :key="index">
<image
v-lazy="item.url"
:data-src="item.url"
class="lazy-image"
:style="{ height: item.height + 'px' }"
/>
</view>
</view>
</template>
<script>
export default {
data() {
return {
images: [
{ url: 'https://example.com/image1.jpg', height: 200 },
{ url: 'https://example.com/image2.jpg', height: 250 },
{ url: 'https://example.com/image3.jpg', height: 300 },
{ url: 'https://example.com/image4.jpg', height: 200 },
{ url: 'https://example.com/image5.jpg', height: 250 },
{ url: 'https://example.com/image6.jpg', height: 300 },
{ url: 'https://example.com/image7.jpg', height: 200 },
{ url: 'https://example.com/image8.jpg', height: 250 },
{ url: 'https://example.com/image9.jpg', height: 300 },
{ url: 'https://example.com/image10.jpg', height: 200 }
]
};
},
directives: {
lazy: {
inserted(el, binding) {
// 设置占位图
el.src = 'https://example.com/placeholder.jpg';
// 创建观察者
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
// 图片进入视口,加载真实图片
el.src = binding.value;
// 停止观察
observer.unobserve(el);
}
});
}, {
threshold: 0.1
});
// 开始观察
observer.observe(el);
// 保存观察者实例,以便后续清理
el._observer = observer;
},
unbind(el) {
// 清理观察者
if (el._observer) {
el._observer.disconnect();
}
}
}
}
};
</script>
<style scoped>
.lazy-load-demo {
padding: 20rpx;
}
.image-item {
margin-bottom: 20rpx;
overflow: hidden;
border-radius: 8rpx;
}
.lazy-image {
width: 100%;
transition: opacity 0.3s ease;
}
.lazy-image[src="https://example.com/placeholder.jpg"] {
opacity: 0.5;
}
</style>案例四:实现网络状态监测与自动重试
问题描述
应用在网络不稳定的情况下,用户体验较差,需要手动刷新才能重新加载数据。
解决方案
实现网络状态监测,当网络从离线恢复到在线时,自动重试失败的请求。
代码示例
// utils/network.js
class NetworkManager {
constructor() {
this.isOnline = true;
this.pendingRequests = [];
this.initNetworkMonitor();
}
// 初始化网络监测
initNetworkMonitor() {
// 监听网络状态变化
uni.onNetworkStatusChange(res => {
this.isOnline = res.isConnected;
if (res.isConnected) {
// 网络恢复,处理待处理的请求
this.handlePendingRequests();
uni.showToast({ title: '网络已恢复', icon: 'success' });
} else {
uni.showToast({ title: '网络连接已断开', icon: 'none' });
}
});
// 初始检查
uni.getNetworkType({
success: (res) => {
this.isOnline = res.networkType !== 'none';
}
});
}
// 添加待处理的请求
addPendingRequest(requestFn) {
this.pendingRequests.push(requestFn);
}
// 处理待处理的请求
handlePendingRequests() {
while (this.pendingRequests.length > 0) {
const requestFn = this.pendingRequests.shift();
try {
requestFn();
} catch (error) {
console.error('处理待处理请求失败:', error);
}
}
}
// 检查网络状态
checkNetwork() {
return new Promise((resolve) => {
if (this.isOnline) {
resolve(true);
} else {
uni.getNetworkType({
success: (res) => {
this.isOnline = res.networkType !== 'none';
resolve(this.isOnline);
},
fail: () => {
resolve(false);
}
});
}
});
}
// 带网络检查的请求包装
async requestWithNetworkCheck(requestFn) {
const isOnline = await this.checkNetwork();
if (isOnline) {
try {
return await requestFn();
} catch (error) {
// 请求失败,添加到待处理队列
this.addPendingRequest(requestFn);
throw error;
}
} else {
// 网络离线,添加到待处理队列
this.addPendingRequest(requestFn);
throw new Error('网络连接已断开,请检查网络设置');
}
}
}
export default new NetworkManager();使用示例
import request from '@/api/request';
import networkManager from '@/utils/network';
// 带网络检查的请求
export const getHomeData = async () => {
return networkManager.requestWithNetworkCheck(() => {
return request.get('/home/data');
});
};
export const submitOrder = async (data) => {
return networkManager.requestWithNetworkCheck(() => {
return request.post('/order/submit', data);
});
};学习目标
- 了解 uni-app 应用中网络优化的重要性
- 掌握网络请求优化的各种方法和技巧
- 学会实现数据压缩和传输优化
- 理解并应用各种缓存策略
- 掌握网络错误处理和重试机制
- 能够根据实际场景选择合适的网络优化策略
网络优化最佳实践
- 分析网络性能瓶颈:使用浏览器开发者工具或 uni-app 开发者工具分析网络请求性能
- 实施渐进式优化:从最容易实现的优化开始,逐步深入
- 监控网络性能:建立网络性能监控系统,及时发现问题
- 根据网络环境调整策略:在不同网络环境下使用不同的优化策略
- 用户体验优先:优化网络性能的同时,确保用户体验不受影响
- 持续优化:网络优化是一个持续的过程,需要不断调整和改进
总结
网络优化是 uni-app 应用开发中一个重要的环节,通过合理的网络请求优化、数据压缩、缓存策略和错误处理,可以显著提升应用的性能和用户体验。
在实际开发中,开发者应该根据应用的具体情况,选择合适的优化策略。例如,对于数据更新频繁的应用,应该注重实时性;对于数据更新不频繁的应用,应该注重缓存策略。
通过本教程的学习,你应该掌握了 uni-app 网络优化的核心知识点和实用技巧,能够在实际项目中应用这些知识,开发出性能优异、用户体验良好的应用。
记住,优秀的应用不仅功能丰富,还要响应迅速、流畅稳定,而良好的网络优化是实现这一目标的关键因素之一。