引言

随着移动互联网的快速发展,小程序已成为重要的应用形态。然而,小程序的加载性能直接影响用户体验,特别是在网络环境较差的情况下。优化小程序加载性能不仅能提升用户体验,还能提高用户留存率和转化率。

本文将深入探讨小程序加载性能优化的核心策略,从启动优化到资源加载,从代码优化到用户体验提升,提供完整的性能优化解决方案。

小程序性能指标分析

1. 关键性能指标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// 小程序性能监控工具
class MiniProgramPerformanceMonitor {
constructor() {
this.metrics = {
// 启动时间指标
launchTime: 0,
firstScreenTime: 0,
firstInteractionTime: 0,

// 资源加载指标
resourceLoadTime: {},
networkLatency: 0,

// 渲染性能指标
renderTime: 0,
fps: 0,
memoryUsage: 0
};
}

// 监控启动性能
monitorLaunchPerformance() {
const startTime = Date.now();

// 监听小程序启动完成
wx.onAppShow(() => {
this.metrics.launchTime = Date.now() - startTime;
this.reportMetrics('launch', this.metrics.launchTime);
});

// 监听首屏渲染完成
wx.onReady(() => {
this.metrics.firstScreenTime = Date.now() - startTime;
this.reportMetrics('firstScreen', this.metrics.firstScreenTime);
});
}

// 监控资源加载性能
monitorResourcePerformance() {
const originalRequest = wx.request;

wx.request = (options) => {
const startTime = Date.now();

return originalRequest({
...options,
success: (res) => {
const loadTime = Date.now() - startTime;
this.metrics.resourceLoadTime[options.url] = loadTime;
this.reportMetrics('resource', loadTime, options.url);

if (options.success) {
options.success(res);
}
},
fail: (err) => {
const loadTime = Date.now() - startTime;
this.reportMetrics('resourceError', loadTime, options.url);

if (options.fail) {
options.fail(err);
}
}
});
};
}

// 上报性能数据
reportMetrics(type, value, url = '') {
console.log(`性能指标 - ${type}: ${value}ms`, url);

// 实际项目中可以上报到监控平台
// this.sendToMonitoringPlatform(type, value, url);
}
}

// 使用性能监控
const performanceMonitor = new MiniProgramPerformanceMonitor();
performanceMonitor.monitorLaunchPerformance();
performanceMonitor.monitorResourcePerformance();

2. 性能基准测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 性能基准测试工具
class PerformanceBenchmark {
constructor() {
this.benchmarks = {
// 启动时间基准
launchTime: {
excellent: 1000, // 1秒内
good: 2000, // 2秒内
acceptable: 3000 // 3秒内
},

// 首屏时间基准
firstScreenTime: {
excellent: 1500, // 1.5秒内
good: 2500, // 2.5秒内
acceptable: 4000 // 4秒内
},

// 资源加载基准
resourceLoadTime: {
excellent: 500, // 0.5秒内
good: 1000, // 1秒内
acceptable: 2000 // 2秒内
}
};
}

// 评估性能等级
evaluatePerformance(type, value) {
const benchmark = this.benchmarks[type];
if (!benchmark) return 'unknown';

if (value <= benchmark.excellent) return 'excellent';
if (value <= benchmark.good) return 'good';
if (value <= benchmark.acceptable) return 'acceptable';
return 'poor';
}

// 生成性能报告
generateReport(metrics) {
const report = {
overall: 'good',
details: {},
recommendations: []
};

Object.keys(metrics).forEach(key => {
const level = this.evaluatePerformance(key, metrics[key]);
report.details[key] = {
value: metrics[key],
level: level
};

if (level === 'poor' || level === 'acceptable') {
report.recommendations.push(this.getRecommendation(key));
}
});

return report;
}

// 获取优化建议
getRecommendation(type) {
const recommendations = {
launchTime: '优化小程序启动流程,减少不必要的初始化操作',
firstScreenTime: '优化首屏渲染,使用骨架屏和懒加载',
resourceLoadTime: '优化资源加载,使用CDN和资源压缩'
};

return recommendations[type] || '需要进一步分析性能问题';
}
}

启动优化策略

1. 代码分包优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// app.json - 分包配置
{
"pages": [
"pages/index/index",
"pages/user/user"
],
"subPackages": [
{
"root": "pages/shop",
"name": "shop",
"pages": [
"product/list",
"product/detail",
"cart/index",
"order/list"
]
},
{
"root": "pages/social",
"name": "social",
"pages": [
"feed/list",
"feed/detail",
"comment/list"
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["shop"]
}
}
}

// 动态加载分包
class SubPackageLoader {
constructor() {
this.loadedPackages = new Set();
}

// 预加载分包
async preloadSubPackage(packageName) {
if (this.loadedPackages.has(packageName)) {
return Promise.resolve();
}

try {
await new Promise((resolve, reject) => {
wx.loadSubpackage({
name: packageName,
success: () => {
this.loadedPackages.add(packageName);
resolve();
},
fail: reject
});
});
} catch (error) {
console.error(`分包${packageName}加载失败:`, error);
throw error;
}
}

// 智能预加载
async smartPreload(currentPage) {
const preloadRules = {
'pages/index/index': ['shop'],
'pages/shop/product/list': ['social'],
'pages/user/user': ['shop', 'social']
};

const packagesToLoad = preloadRules[currentPage] || [];

for (const packageName of packagesToLoad) {
if (!this.loadedPackages.has(packageName)) {
try {
await this.preloadSubPackage(packageName);
} catch (error) {
console.warn(`预加载分包${packageName}失败:`, error);
}
}
}
}
}

// 使用分包加载器
const subPackageLoader = new SubPackageLoader();

// 在页面onLoad中预加载
Page({
onLoad() {
subPackageLoader.smartPreload(getCurrentPages()[0].route);
}
});

2. 启动流程优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// 启动流程优化
class LaunchOptimizer {
constructor() {
this.startTime = Date.now();
this.initSteps = [];
}

// 异步初始化
async asyncInit() {
// 1. 优先初始化核心功能
await this.initCoreFeatures();

// 2. 延迟初始化非核心功能
setTimeout(() => {
this.initNonCoreFeatures();
}, 100);

// 3. 后台初始化辅助功能
setTimeout(() => {
this.initAuxiliaryFeatures();
}, 500);
}

// 初始化核心功能
async initCoreFeatures() {
const coreSteps = [
this.initUserInfo(),
this.initAppConfig(),
this.initNetworkConfig()
];

// 并行执行核心初始化
await Promise.all(coreSteps);

this.recordStep('core', Date.now() - this.startTime);
}

// 初始化非核心功能
async initNonCoreFeatures() {
const nonCoreSteps = [
this.initAnalytics(),
this.initPushService(),
this.initCacheService()
];

// 串行执行非核心初始化
for (const step of nonCoreSteps) {
try {
await step;
} catch (error) {
console.warn('非核心功能初始化失败:', error);
}
}

this.recordStep('nonCore', Date.now() - this.startTime);
}

// 初始化辅助功能
async initAuxiliaryFeatures() {
const auxiliarySteps = [
this.initThemeService(),
this.initLogService(),
this.initDebugService()
];

// 后台执行辅助初始化
auxiliarySteps.forEach(async (step) => {
try {
await step;
} catch (error) {
console.warn('辅助功能初始化失败:', error);
}
});

this.recordStep('auxiliary', Date.now() - this.startTime);
}

// 记录初始化步骤
recordStep(stepName, time) {
this.initSteps.push({
step: stepName,
time: time,
duration: time - (this.initSteps[this.initSteps.length - 1]?.time || this.startTime)
});

console.log(`初始化步骤 ${stepName} 完成,耗时: ${time - this.startTime}ms`);
}

// 获取初始化报告
getInitReport() {
return {
totalTime: Date.now() - this.startTime,
steps: this.initSteps,
recommendations: this.generateRecommendations()
};
}

// 生成优化建议
generateRecommendations() {
const recommendations = [];

this.initSteps.forEach(step => {
if (step.duration > 1000) {
recommendations.push(`优化${step.step}步骤,当前耗时${step.duration}ms`);
}
});

return recommendations;
}
}

// 具体初始化方法
class LaunchOptimizer {
// 初始化用户信息
async initUserInfo() {
return new Promise((resolve) => {
wx.getUserInfo({
success: (res) => {
this.userInfo = res.userInfo;
resolve();
},
fail: () => {
// 用户信息获取失败不影响启动
resolve();
}
});
});
}

// 初始化应用配置
async initAppConfig() {
// 从本地存储读取配置
const config = wx.getStorageSync('appConfig') || {};
this.appConfig = {
theme: config.theme || 'light',
language: config.language || 'zh-CN',
version: config.version || '1.0.0'
};
}

// 初始化网络配置
async initNetworkConfig() {
// 检测网络状态
const networkInfo = await new Promise((resolve) => {
wx.getNetworkType({
success: resolve,
fail: () => resolve({ networkType: 'unknown' })
});
});

this.networkConfig = {
type: networkInfo.networkType,
isSlow: networkInfo.networkType === '2g' || networkInfo.networkType === 'slow'
};
}
}

资源加载优化

1. 图片资源优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// 图片资源优化工具
class ImageOptimizer {
constructor() {
this.imageCache = new Map();
this.loadingImages = new Set();
}

// 智能图片加载
async loadImage(src, options = {}) {
const {
placeholder = '/images/placeholder.png',
lazy = true,
quality = 'auto',
format = 'webp'
} = options;

// 检查缓存
if (this.imageCache.has(src)) {
return this.imageCache.get(src);
}

// 检查是否正在加载
if (this.loadingImages.has(src)) {
return this.waitForImage(src);
}

this.loadingImages.add(src);

try {
const optimizedSrc = this.optimizeImageSrc(src, { quality, format });
const imageInfo = await this.loadImageInfo(optimizedSrc);

this.imageCache.set(src, imageInfo);
this.loadingImages.delete(src);

return imageInfo;
} catch (error) {
this.loadingImages.delete(src);
console.error('图片加载失败:', src, error);
throw error;
}
}

// 优化图片URL
optimizeImageSrc(src, options) {
const { quality, format } = options;

// 添加图片优化参数
const url = new URL(src);

if (quality !== 'auto') {
url.searchParams.set('quality', quality);
}

if (format) {
url.searchParams.set('format', format);
}

// 添加尺寸参数
url.searchParams.set('w', '750'); // 小程序标准宽度

return url.toString();
}

// 加载图片信息
loadImageInfo(src) {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src: src,
success: (res) => {
resolve({
src: src,
width: res.width,
height: res.height,
path: res.path
});
},
fail: reject
});
});
}

// 等待图片加载完成
async waitForImage(src) {
return new Promise((resolve) => {
const checkInterval = setInterval(() => {
if (this.imageCache.has(src)) {
clearInterval(checkInterval);
resolve(this.imageCache.get(src));
}
}, 100);
});
}

// 预加载关键图片
async preloadCriticalImages(imageList) {
const loadPromises = imageList.map(src =>
this.loadImage(src, { lazy: false })
);

try {
await Promise.all(loadPromises);
console.log('关键图片预加载完成');
} catch (error) {
console.warn('部分关键图片预加载失败:', error);
}
}
}

// 图片懒加载组件
Component({
properties: {
src: String,
placeholder: String,
lazy: {
type: Boolean,
value: true
}
},

data: {
loaded: false,
error: false,
imageInfo: null
},

lifetimes: {
attached() {
if (this.data.lazy) {
this.observeIntersection();
} else {
this.loadImage();
}
}
},

methods: {
// 监听元素进入视口
observeIntersection() {
const query = this.createSelectorQuery();
query.boundingClientRect();
query.exec((res) => {
if (res[0]) {
const rect = res[0];
if (rect.top < wx.getSystemInfoSync().windowHeight) {
this.loadImage();
}
}
});
},

// 加载图片
async loadImage() {
try {
const imageOptimizer = new ImageOptimizer();
const imageInfo = await imageOptimizer.loadImage(this.data.src, {
placeholder: this.data.placeholder
});

this.setData({
loaded: true,
imageInfo: imageInfo
});
} catch (error) {
this.setData({
error: true
});
}
}
}
});

2. 网络请求优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// 网络请求优化工具
class NetworkOptimizer {
constructor() {
this.requestCache = new Map();
this.requestQueue = [];
this.maxConcurrent = 3;
this.currentConcurrent = 0;
}

// 智能请求
async smartRequest(options) {
const {
url,
method = 'GET',
data = {},
cache = true,
timeout = 10000,
retry = 3
} = options;

// 检查缓存
if (cache && method === 'GET') {
const cached = this.getCachedRequest(url, data);
if (cached) {
return cached;
}
}

// 添加到请求队列
return new Promise((resolve, reject) => {
this.requestQueue.push({
options: { url, method, data, timeout, retry },
resolve,
reject
});

this.processQueue();
});
}

// 处理请求队列
async processQueue() {
if (this.currentConcurrent >= this.maxConcurrent || this.requestQueue.length === 0) {
return;
}

this.currentConcurrent++;
const request = this.requestQueue.shift();

try {
const result = await this.executeRequest(request.options);

// 缓存GET请求结果
if (request.options.method === 'GET') {
this.setCachedRequest(request.options.url, request.options.data, result);
}

request.resolve(result);
} catch (error) {
request.reject(error);
} finally {
this.currentConcurrent--;
this.processQueue();
}
}

// 执行请求
async executeRequest(options) {
const { url, method, data, timeout, retry } = options;
let lastError;

for (let i = 0; i < retry; i++) {
try {
const result = await this.makeRequest(url, method, data, timeout);
return result;
} catch (error) {
lastError = error;

// 指数退避重试
if (i < retry - 1) {
await this.delay(Math.pow(2, i) * 1000);
}
}
}

throw lastError;
}

// 发起网络请求
makeRequest(url, method, data, timeout) {
return new Promise((resolve, reject) => {
const requestOptions = {
url,
method,
data,
timeout,
success: resolve,
fail: reject
};

wx.request(requestOptions);
});
}

// 获取缓存请求
getCachedRequest(url, data) {
const key = this.generateCacheKey(url, data);
const cached = this.requestCache.get(key);

if (cached && Date.now() - cached.timestamp < 300000) { // 5分钟缓存
return cached.data;
}

return null;
}

// 设置缓存请求
setCachedRequest(url, data, result) {
const key = this.generateCacheKey(url, data);
this.requestCache.set(key, {
data: result,
timestamp: Date.now()
});
}

// 生成缓存键
generateCacheKey(url, data) {
return `${url}_${JSON.stringify(data)}`;
}

// 延迟函数
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

// 批量请求
async batchRequest(requests) {
const promises = requests.map(request =>
this.smartRequest(request)
);

return Promise.allSettled(promises);
}
}

// 使用网络优化器
const networkOptimizer = new NetworkOptimizer();

// 页面中使用
Page({
async loadData() {
try {
const [userInfo, productList, config] = await Promise.all([
networkOptimizer.smartRequest({
url: '/api/user/info',
cache: true
}),
networkOptimizer.smartRequest({
url: '/api/products',
cache: true
}),
networkOptimizer.smartRequest({
url: '/api/config',
cache: true
})
]);

this.setData({
userInfo,
productList,
config
});
} catch (error) {
console.error('数据加载失败:', error);
}
}
});

渲染性能优化

1. 页面渲染优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// 页面渲染优化工具
class RenderOptimizer {
constructor() {
this.renderQueue = [];
this.isRendering = false;
}

// 批量更新数据
batchUpdate(updates) {
this.renderQueue.push(...updates);

if (!this.isRendering) {
this.processRenderQueue();
}
}

// 处理渲染队列
async processRenderQueue() {
this.isRendering = true;

while (this.renderQueue.length > 0) {
const batch = this.renderQueue.splice(0, 10); // 每批处理10个更新

// 合并更新
const mergedUpdate = this.mergeUpdates(batch);

// 执行更新
await this.executeUpdate(mergedUpdate);

// 让出执行权
await this.nextTick();
}

this.isRendering = false;
}

// 合并更新
mergeUpdates(updates) {
const merged = {};

updates.forEach(update => {
Object.assign(merged, update);
});

return merged;
}

// 执行更新
executeUpdate(update) {
return new Promise((resolve) => {
this.setData(update, () => {
resolve();
});
});
}

// 下一帧执行
nextTick() {
return new Promise(resolve => {
setTimeout(resolve, 0);
});
}
}

// 虚拟列表组件
Component({
properties: {
items: Array,
itemHeight: Number,
containerHeight: Number
},

data: {
visibleItems: [],
scrollTop: 0,
startIndex: 0,
endIndex: 0
},

lifetimes: {
attached() {
this.calculateVisibleItems();
}
},

observers: {
'items, itemHeight, containerHeight': function() {
this.calculateVisibleItems();
}
},

methods: {
// 计算可见项目
calculateVisibleItems() {
const { items, itemHeight, containerHeight } = this.data;

if (!items || !itemHeight || !containerHeight) return;

const visibleCount = Math.ceil(containerHeight / itemHeight) + 2; // 多渲染2个
const startIndex = Math.floor(this.data.scrollTop / itemHeight);
const endIndex = Math.min(startIndex + visibleCount, items.length);

const visibleItems = items.slice(startIndex, endIndex).map((item, index) => ({
...item,
index: startIndex + index,
top: (startIndex + index) * itemHeight
}));

this.setData({
visibleItems,
startIndex,
endIndex
});
},

// 滚动事件
onScroll(e) {
const scrollTop = e.detail.scrollTop;

if (Math.abs(scrollTop - this.data.scrollTop) > this.data.itemHeight) {
this.setData({ scrollTop });
this.calculateVisibleItems();
}
}
}
});

2. 动画性能优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 动画性能优化
class AnimationOptimizer {
constructor() {
this.animations = new Map();
this.rafId = null;
}

// 创建高性能动画
createAnimation(options) {
const {
duration = 300,
timingFunction = 'ease',
delay = 0,
transformOrigin = '50% 50%'
} = options;

const animation = wx.createAnimation({
duration,
timingFunction,
delay,
transformOrigin
});

return animation;
}

// 批量动画
batchAnimate(animations) {
const promises = animations.map(animation =>
this.executeAnimation(animation)
);

return Promise.all(promises);
}

// 执行动画
executeAnimation(animation) {
return new Promise((resolve) => {
animation.step();

// 使用requestAnimationFrame优化动画
this.rafId = requestAnimationFrame(() => {
resolve();
});
});
}

// 停止动画
stopAnimation() {
if (this.rafId) {
cancelAnimationFrame(this.rafId);
this.rafId = null;
}
}
}

// 使用动画优化器
const animationOptimizer = new AnimationOptimizer();

// 页面中使用
Page({
data: {
animationData: {}
},

// 淡入动画
fadeIn() {
const animation = animationOptimizer.createAnimation({
duration: 500,
timingFunction: 'ease-in'
});

animation.opacity(1).step();

this.setData({
animationData: animation.export()
});
},

// 滑动动画
slideIn() {
const animation = animationOptimizer.createAnimation({
duration: 300,
timingFunction: 'ease-out'
});

animation.translateX(0).step();

this.setData({
animationData: animation.export()
});
}
});

用户体验优化

1. 骨架屏实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 骨架屏组件
Component({
properties: {
loading: {
type: Boolean,
value: true
},
skeleton: {
type: Object,
value: {}
}
},

data: {
skeletonData: {}
},

lifetimes: {
attached() {
this.generateSkeleton();
}
},

observers: {
'skeleton': function() {
this.generateSkeleton();
}
},

methods: {
// 生成骨架屏数据
generateSkeleton() {
const { skeleton } = this.data;
const skeletonData = {
title: this.createSkeletonItem({ width: '60%', height: '32rpx' }),
content: this.createSkeletonItem({ width: '100%', height: '24rpx' }),
avatar: this.createSkeletonItem({ width: '80rpx', height: '80rpx', borderRadius: '50%' }),
button: this.createSkeletonItem({ width: '120rpx', height: '60rpx', borderRadius: '8rpx' })
};

this.setData({
skeletonData: { ...skeletonData, ...skeleton }
});
},

// 创建骨架屏项目
createSkeletonItem(style) {
return {
style: Object.keys(style).map(key =>
`${key}: ${style[key]}`
).join('; '),
class: 'skeleton-item'
};
}
}
});

// 骨架屏样式
const skeletonStyles = `
.skeleton-item {
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s infinite;
}

@keyframes skeleton-loading {
0% {
background-position: 200% 0;
}
100% {
background-position: -200% 0;
}
}
`;

2. 加载状态管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// 加载状态管理器
class LoadingManager {
constructor() {
this.loadingStates = new Map();
this.globalLoading = false;
}

// 设置加载状态
setLoading(key, loading) {
this.loadingStates.set(key, loading);
this.updateGlobalLoading();
}

// 获取加载状态
getLoading(key) {
return this.loadingStates.get(key) || false;
}

// 更新全局加载状态
updateGlobalLoading() {
const hasLoading = Array.from(this.loadingStates.values()).some(loading => loading);
this.globalLoading = hasLoading;
}

// 批量设置加载状态
setBatchLoading(states) {
Object.keys(states).forEach(key => {
this.setLoading(key, states[key]);
});
}

// 清除加载状态
clearLoading(key) {
this.loadingStates.delete(key);
this.updateGlobalLoading();
}

// 清除所有加载状态
clearAllLoading() {
this.loadingStates.clear();
this.globalLoading = false;
}
}

// 使用加载状态管理器
const loadingManager = new LoadingManager();

// 页面中使用
Page({
data: {
loading: {
userInfo: false,
productList: false,
config: false
}
},

async loadUserInfo() {
loadingManager.setLoading('userInfo', true);

try {
const userInfo = await this.fetchUserInfo();
this.setData({ userInfo });
} catch (error) {
console.error('用户信息加载失败:', error);
} finally {
loadingManager.setLoading('userInfo', false);
}
},

async loadProductList() {
loadingManager.setLoading('productList', true);

try {
const productList = await this.fetchProductList();
this.setData({ productList });
} catch (error) {
console.error('商品列表加载失败:', error);
} finally {
loadingManager.setLoading('productList', false);
}
}
});

性能监控与调试

1. 性能监控工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// 性能监控工具
class PerformanceMonitor {
constructor() {
this.metrics = {
launch: 0,
firstScreen: 0,
network: [],
render: [],
memory: []
};

this.startTime = Date.now();
this.setupMonitoring();
}

// 设置监控
setupMonitoring() {
// 监控启动时间
this.monitorLaunch();

// 监控网络请求
this.monitorNetwork();

// 监控内存使用
this.monitorMemory();

// 监控渲染性能
this.monitorRender();
}

// 监控启动时间
monitorLaunch() {
wx.onAppShow(() => {
this.metrics.launch = Date.now() - this.startTime;
this.reportMetric('launch', this.metrics.launch);
});

wx.onReady(() => {
this.metrics.firstScreen = Date.now() - this.startTime;
this.reportMetric('firstScreen', this.metrics.firstScreen);
});
}

// 监控网络请求
monitorNetwork() {
const originalRequest = wx.request;

wx.request = (options) => {
const startTime = Date.now();

return originalRequest({
...options,
success: (res) => {
const duration = Date.now() - startTime;
this.metrics.network.push({
url: options.url,
method: options.method,
duration,
success: true
});

if (options.success) {
options.success(res);
}
},
fail: (err) => {
const duration = Date.now() - startTime;
this.metrics.network.push({
url: options.url,
method: options.method,
duration,
success: false
});

if (options.fail) {
options.fail(err);
}
}
});
};
}

// 监控内存使用
monitorMemory() {
setInterval(() => {
wx.getSystemInfo({
success: (res) => {
this.metrics.memory.push({
timestamp: Date.now(),
usedJSHeapSize: res.usedJSHeapSize,
totalJSHeapSize: res.totalJSHeapSize
});
}
});
}, 5000);
}

// 监控渲染性能
monitorRender() {
let frameCount = 0;
let lastTime = Date.now();

const countFrames = () => {
frameCount++;
const currentTime = Date.now();

if (currentTime - lastTime >= 1000) {
const fps = frameCount;
this.metrics.render.push({
timestamp: currentTime,
fps
});

frameCount = 0;
lastTime = currentTime;
}

requestAnimationFrame(countFrames);
};

countFrames();
}

// 上报性能指标
reportMetric(type, value) {
console.log(`性能指标 - ${type}: ${value}ms`);

// 实际项目中可以上报到监控平台
// this.sendToMonitoringPlatform(type, value);
}

// 获取性能报告
getPerformanceReport() {
return {
launch: this.metrics.launch,
firstScreen: this.metrics.firstScreen,
network: this.analyzeNetworkMetrics(),
memory: this.analyzeMemoryMetrics(),
render: this.analyzeRenderMetrics()
};
}

// 分析网络指标
analyzeNetworkMetrics() {
const network = this.metrics.network;
const successCount = network.filter(req => req.success).length;
const totalCount = network.length;
const avgDuration = network.reduce((sum, req) => sum + req.duration, 0) / totalCount;

return {
totalRequests: totalCount,
successRate: successCount / totalCount,
averageDuration: avgDuration
};
}

// 分析内存指标
analyzeMemoryMetrics() {
const memory = this.metrics.memory;
if (memory.length === 0) return null;

const latest = memory[memory.length - 1];
const maxUsed = Math.max(...memory.map(m => m.usedJSHeapSize));

return {
currentUsed: latest.usedJSHeapSize,
maxUsed,
trend: this.calculateTrend(memory.map(m => m.usedJSHeapSize))
};
}

// 分析渲染指标
analyzeRenderMetrics() {
const render = this.metrics.render;
if (render.length === 0) return null;

const avgFps = render.reduce((sum, r) => sum + r.fps, 0) / render.length;
const minFps = Math.min(...render.map(r => r.fps));

return {
averageFps: avgFps,
minFps,
smoothness: minFps >= 30 ? 'good' : 'poor'
};
}

// 计算趋势
calculateTrend(values) {
if (values.length < 2) return 'stable';

const first = values[0];
const last = values[values.length - 1];

if (last > first * 1.1) return 'increasing';
if (last < first * 0.9) return 'decreasing';
return 'stable';
}
}

// 使用性能监控
const performanceMonitor = new PerformanceMonitor();

// 在页面中获取性能报告
Page({
onShow() {
const report = performanceMonitor.getPerformanceReport();
console.log('性能报告:', report);
}
});

2. 调试工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// 调试工具
class DebugTool {
constructor() {
this.isDebugMode = false;
this.logs = [];
this.performanceData = {};
}

// 启用调试模式
enableDebugMode() {
this.isDebugMode = true;
this.setupDebugTools();
}

// 设置调试工具
setupDebugTools() {
// 重写console.log
const originalLog = console.log;
console.log = (...args) => {
if (this.isDebugMode) {
this.logs.push({
timestamp: Date.now(),
type: 'log',
message: args.join(' ')
});
}
originalLog.apply(console, args);
};

// 监听错误
wx.onError((error) => {
if (this.isDebugMode) {
this.logs.push({
timestamp: Date.now(),
type: 'error',
message: error
});
}
});
}

// 记录性能数据
recordPerformance(key, value) {
this.performanceData[key] = value;
}

// 获取调试信息
getDebugInfo() {
return {
logs: this.logs,
performance: this.performanceData,
systemInfo: wx.getSystemInfoSync()
};
}

// 导出调试数据
exportDebugData() {
const debugData = this.getDebugInfo();
const dataStr = JSON.stringify(debugData, null, 2);

// 复制到剪贴板
wx.setClipboardData({
data: dataStr,
success: () => {
wx.showToast({
title: '调试数据已复制',
icon: 'success'
});
}
});
}
}

// 使用调试工具
const debugTool = new DebugTool();

// 在开发环境中启用调试
if (process.env.NODE_ENV === 'development') {
debugTool.enableDebugMode();
}

总结

小程序加载性能优化是一个系统性工程,需要从多个维度进行优化:

  1. 启动优化:通过代码分包、异步初始化、预加载等策略减少启动时间
  2. 资源优化:优化图片加载、网络请求、缓存策略等提升资源加载效率
  3. 渲染优化:使用虚拟列表、批量更新、动画优化等技术提升渲染性能
  4. 用户体验:通过骨架屏、加载状态管理、错误处理等提升用户体验
  5. 监控调试:建立完善的性能监控体系,及时发现和解决性能问题

通过系统性的优化,可以显著提升小程序的加载性能和用户体验,为用户提供更加流畅的使用体验。

参考资料

  1. 《微信小程序开发文档》
  2. 《小程序性能优化指南》
  3. 《前端性能优化原理与实践》
  4. 《移动端性能优化》
  5. 微信小程序官方性能优化建议