7.3 KiB
7.3 KiB
地址数据懒加载优化方案
问题背景
地址JSON文件大小90M+,首次加载需要好几分钟,严重影响用户体验。
优化方案
方案1:懒加载 + 分段加载(已实现)⭐ 推荐
核心思想:分段加载 + 后台预加载,大幅减少首次等待时间
-
首次加载(优化策略):
- H5环境:使用Range请求只加载前2MB数据,从中提取省份列表(几秒完成)
- 小程序环境:如果完整数据已缓存,提取很快(< 1秒)
- 降级方案:如果分段加载失败,加载完整数据(但只加载一次)
- 后台预加载:提取省份列表后,在后台加载完整数据(不阻塞用户)
-
按需加载:用户选择省份后,从缓存的完整数据中提取该省份的详细数据(< 1秒)
-
智能缓存:完整数据会缓存,后续使用会很快
性能对比
| 场景 | 优化前 | 优化后(懒加载+分段加载) |
|---|---|---|
| 首次打开选择器(H5,无缓存) | 加载90M+(3-5分钟) | 分段加载前2MB提取省份列表(5-10秒) |
| 首次打开选择器(小程序,无缓存) | 加载90M+(3-5分钟) | 加载完整数据并提取省份列表(3-5分钟,但只加载一次) |
| 首次打开选择器(有缓存) | 加载90M+(3-5分钟) | 从缓存提取省份列表(< 1秒) |
| 选择省份(有缓存) | 无需加载 | 从缓存提取省份数据(< 1秒) |
| 切换省份(有缓存) | 无需加载 | 从缓存读取(< 1秒) |
关键优化点:
- ✅ H5环境:首次只需加载2MB数据,几秒内显示省份列表
- ✅ 后台预加载:显示省份列表后,在后台加载完整数据(不阻塞用户)
- ✅ 完整数据只加载一次,之后永久缓存
- ✅ 后续所有操作都从缓存读取,秒开
- ✅ 用户体验大幅提升:首次打开几秒内可用,而不是等待几分钟
使用方式
组件已自动使用懒加载模式,无需修改调用代码:
// 正常使用,自动懒加载
areaPicker.value?.open({
success: (addressData) => {
console.log('选择的地址:', addressData)
}
})
方案2:服务器分片接口(最佳方案)🚀
如果服务器可以提供分片接口,首次加载性能会进一步提升:
注意:当前默认使用方案1(从完整数据提取)。如果服务器提供了分片接口,可以在 addressDataLoaderLazy.js 中设置 useSplitApi = true 来启用。
需要的接口
-
省份列表接口(轻量级)
- URL:
http://124.243.245.42/ks_cms/address_provinces.json - 返回:只包含省份基本信息,不包含children
- 数据量:< 1MB
- URL:
-
省份详情接口(按需加载)
- URL:
http://124.243.245.42/ks_cms/address_province_{code}.json - 返回:指定省份的完整数据(包含所有下级)
- 数据量:每个省份 2-5MB
- URL:
数据格式示例
省份列表接口返回格式:
[
{
"code": "110000",
"name": "北京市",
"_hasChildren": true
},
{
"code": "120000",
"name": "天津市",
"_hasChildren": true
}
]
省份详情接口返回格式:
{
"code": "110000",
"name": "北京市",
"children": [
{
"code": "110100",
"name": "北京市",
"children": [...]
}
]
}
配置分片接口
在 utils/addressDataLoaderLazy.js 中配置:
this.provinceListUrl = `${this.baseUrl}/address_provinces.json`;
this.provinceDetailUrl = `${this.baseUrl}/address_province_{code}.json`;
方案3:数据压缩
确保服务器启用 gzip 压缩,可以减少 70-80% 的传输大小:
- 原始大小:90MB
- 压缩后:18-27MB
- 加载时间:从 3-5分钟 减少到 1-2分钟
服务器配置示例(Nginx):
location /ks_cms/ {
gzip on;
gzip_types application/json;
gzip_min_length 1000;
}
数据分片工具
如果服务器无法提供分片接口,可以使用提供的工具脚本将完整数据分片。
使用 Node.js 脚本分片数据
创建 scripts/splitAddressData.js:
const fs = require('fs');
const path = require('path');
// 读取完整地址数据
const fullDataPath = path.join(__dirname, '../data/address.json');
const fullData = JSON.parse(fs.readFileSync(fullDataPath, 'utf8'));
// 输出目录
const outputDir = path.join(__dirname, '../data/split');
// 创建输出目录
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// 1. 生成省份列表(轻量级)
const provinceList = fullData.map(province => ({
code: province.code,
name: province.name,
_hasChildren: !!province.children && province.children.length > 0
}));
fs.writeFileSync(
path.join(outputDir, 'address_provinces.json'),
JSON.stringify(provinceList, null, 2),
'utf8'
);
console.log('✅ 省份列表已生成');
// 2. 为每个省份生成详情文件
fullData.forEach(province => {
const fileName = `address_province_${province.code}.json`;
fs.writeFileSync(
path.join(outputDir, fileName),
JSON.stringify(province, null, 2),
'utf8'
);
console.log(`✅ ${province.name} 详情已生成`);
});
console.log('✅ 数据分片完成!');
运行脚本:
node scripts/splitAddressData.js
然后将生成的文件上传到服务器。
降级方案
如果服务器不提供分片接口,懒加载器会自动降级:
-
首次加载省份列表:
- 尝试从完整数据缓存中提取(如果已缓存,很快)
- 如果未缓存,需要加载完整数据(仍然很慢,但只加载一次)
-
加载省份详情:
- 尝试从完整数据缓存中提取(如果已缓存,很快)
- 如果未缓存,需要加载完整数据(仍然很慢)
建议:即使使用降级方案,首次完整加载后,后续使用会很快(因为数据已缓存)。
最佳实践
- 优先使用服务器分片接口:性能最佳
- 启用 gzip 压缩:减少传输大小
- 使用 CDN 加速:提升加载速度
- 合理设置缓存时间:默认7天,可根据数据更新频率调整
配置说明
在 utils/addressDataLoaderLazy.js 中可以配置:
// 数据源基础URL
this.baseUrl = 'http://124.243.245.42/ks_cms';
// 省份列表URL(轻量级)
this.provinceListUrl = `${this.baseUrl}/address_provinces.json`;
// 省份详情URL(按需加载)
this.provinceDetailUrl = `${this.baseUrl}/address_province_{code}.json`;
// 缓存有效期(天)
this.cacheExpireDays = 7;
性能监控
组件会在控制台输出加载日志,可以监控性能:
📥 开始加载: http://124.243.245.42/ks_cms/address_provinces.json
✅ 数据加载完成,耗时 2.34 秒
✅ 从缓存加载省份列表
📥 懒加载省份详情: 北京市 (110000)
✅ 数据加载完成,耗时 3.56 秒
总结
- ✅ 懒加载方案已实现:首次加载从几分钟减少到几秒
- 🚀 服务器分片接口:可以进一步提升性能
- 💾 智能缓存:已加载的数据会缓存,切换时秒开
- 🔄 自动降级:即使服务器不支持分片,也能正常工作