性能优化 #
一、性能指标 #
1.1 关键指标 #
| 指标 | 说明 | 目标值 |
|---|---|---|
| 首屏时间 | 首次内容渲染时间 | < 1.5s |
| 可交互时间 | 页面可交互时间 | < 3s |
| 内存占用 | 应用内存使用 | < 100MB |
| 包体积 | 应用安装包大小 | < 50MB |
1.2 性能监控 #
typescript
// src/utils/performance.ts
export class PerformanceMonitor {
private static metrics = new Map<string, number>();
static startMeasure(name: string): void {
this.metrics.set(name, performance.now());
}
static endMeasure(name: string): number {
const start = this.metrics.get(name);
if (!start) return 0;
const duration = performance.now() - start;
this.metrics.delete(name);
console.log(`[Performance] ${name}: ${duration.toFixed(2)}ms`);
return duration;
}
static measureAppStart(): void {
window.addEventListener('load', () => {
const timing = performance.timing;
const metrics = {
DNS: timing.domainLookupEnd - timing.domainLookupStart,
TCP: timing.connectEnd - timing.connectStart,
TTFB: timing.responseStart - timing.requestStart,
Download: timing.responseEnd - timing.responseStart,
DOMReady: timing.domContentLoadedEventEnd - timing.navigationStart,
Load: timing.loadEventEnd - timing.navigationStart
};
console.table(metrics);
});
}
}
二、启动优化 #
2.1 启动画面配置 #
json
// capacitor.config.json
{
"plugins": {
"SplashScreen": {
"launchShowDuration": 2000,
"backgroundColor": "#ffffff",
"showSpinner": false,
"splashFullScreen": true,
"splashImmersive": true
}
}
}
2.2 延迟加载 #
typescript
// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
// 延迟加载非关键组件
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<React.Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</React.Suspense>
);
}
// 延迟初始化非关键服务
async function initNonCriticalServices() {
await import('./services/analytics');
await import('./services/push-notifications');
}
// 在应用启动后延迟加载
setTimeout(initNonCriticalServices, 3000);
2.3 代码分割 #
typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom'],
'vendor-router': ['react-router-dom'],
'vendor-ui': ['@ionic/react']
}
}
}
}
});
2.4 预加载关键资源 #
html
<!-- index.html -->
<head>
<!-- 预加载关键CSS -->
<link rel="preload" href="/assets/index.css" as="style">
<!-- 预加载关键字体 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<!-- 预连接API服务器 -->
<link rel="preconnect" href="https://api.example.com">
<link rel="dns-prefetch" href="https://cdn.example.com">
</head>
三、WebView优化 #
3.1 iOS WebView优化 #
swift
// ios/App/App/AppDelegate.swift
import UIKit
import Capacitor
import WebKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 优化WebView配置
optimizeWebView()
return true
}
private func optimizeWebView() {
// 预热WebView
let config = WKWebViewConfiguration()
config.preferences.javaScriptEnabled = true
config.preferences.javaScriptCanOpenWindowsAutomatically = false
// 启用GPU加速
config.allowsInlineMediaPlayback = true
// 预加载WebView
_ = WKWebView(frame: .zero, configuration: config)
}
}
3.2 Android WebView优化 #
java
// android/app/src/main/java/com/company/app/MainActivity.java
package com.company.app;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
import com.getcapacitor.BridgeActivity;
public class MainActivity extends BridgeActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
// 预热WebView
WebView.setWebContentsDebuggingEnabled(false);
super.onCreate(savedInstanceState);
// 优化WebView设置
optimizeWebView();
}
private void optimizeWebView() {
WebView webView = getBridge().getWebView();
WebSettings settings = webView.getSettings();
// 启用缓存
settings.setCacheMode(WebSettings.LOAD_DEFAULT);
settings.setDomStorageEnabled(true);
// 启用硬件加速
webView.setLayerType(WebView.LAYER_TYPE_HARDWARE, null);
// 优化渲染
settings.setRenderPriority(WebSettings.RenderPriority.HIGH);
settings.setEnableSmoothTransition(true);
}
}
3.3 Capacitor配置优化 #
json
// capacitor.config.json
{
"ios": {
"scrollEnabled": true,
"preferredContentMode": "mobile"
},
"android": {
"webContentsDebuggingEnabled": false
}
}
四、内存管理 #
4.1 内存监控 #
typescript
// src/utils/memory-monitor.ts
export class MemoryMonitor {
private static interval: number | null = null;
static start(intervalMs: number = 5000): void {
this.interval = window.setInterval(() => {
this.logMemoryUsage();
}, intervalMs);
}
static stop(): void {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
}
private static logMemoryUsage(): void {
// @ts-ignore - performance.memory是Chrome特有API
if (performance.memory) {
// @ts-ignore
const memory = performance.memory;
console.log({
usedJSHeapSize: `${(memory.usedJSHeapSize / 1048576).toFixed(2)} MB`,
totalJSHeapSize: `${(memory.totalJSHeapSize / 1048576).toFixed(2)} MB`,
jsHeapSizeLimit: `${(memory.jsHeapSizeLimit / 1048576).toFixed(2)} MB`
});
}
}
}
4.2 内存泄漏防护 #
typescript
// src/utils/cleanup.ts
export class ResourceManager {
private resources: Set<() => void> = new Set();
register(cleanup: () => void): () => void {
this.resources.add(cleanup);
return () => this.resources.delete(cleanup);
}
cleanup(): void {
this.resources.forEach(fn => fn());
this.resources.clear();
}
}
// 使用示例
const resourceManager = new ResourceManager();
// 注册事件监听器
const removeListener = addEventListener('resize', handler);
resourceManager.register(removeListener);
// 清理资源
resourceManager.cleanup();
4.3 图片优化 #
typescript
// src/utils/image-loader.ts
export class ImageLoader {
private static cache = new Map<string, string>();
static async load(url: string, options?: { width?: number; quality?: number }): Promise<string> {
const cacheKey = `${url}-${options?.width}-${options?.quality}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey)!;
}
// 使用响应式图片
const optimizedUrl = this.getOptimizedUrl(url, options);
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
this.cache.set(cacheKey, optimizedUrl);
resolve(optimizedUrl);
};
img.onerror = reject;
img.src = optimizedUrl;
});
}
private static getOptimizedUrl(url: string, options?: { width?: number; quality?: number }): string {
if (!options) return url;
const params = new URLSearchParams();
if (options.width) params.set('w', options.width.toString());
if (options.quality) params.set('q', options.quality.toString());
return `${url}?${params.toString()}`;
}
static preload(urls: string[]): Promise<void[]> {
return Promise.all(urls.map(url => this.load(url)));
}
}
五、网络优化 #
5.1 请求优化 #
typescript
// src/services/api-cache.ts
export class ApiCache {
private static cache = new Map<string, { data: any; timestamp: number }>();
private static defaultTTL = 5 * 60 * 1000; // 5分钟
static async get<T>(url: string, ttl: number = this.defaultTTL): Promise<T> {
const cached = this.cache.get(url);
if (cached && Date.now() - cached.timestamp < ttl) {
return cached.data;
}
const response = await fetch(url);
const data = await response.json();
this.cache.set(url, { data, timestamp: Date.now() });
return data;
}
static invalidate(url: string): void {
this.cache.delete(url);
}
static clear(): void {
this.cache.clear();
}
}
5.2 请求去重 #
typescript
// src/services/request-dedup.ts
export class RequestDeduplicator {
private static pending = new Map<string, Promise<any>>();
static async fetch<T>(url: string, options?: RequestInit): Promise<T> {
const key = `${url}-${JSON.stringify(options)}`;
if (this.pending.has(key)) {
return this.pending.get(key)!;
}
const promise = fetch(url, options)
.then(res => res.json())
.finally(() => this.pending.delete(key));
this.pending.set(key, promise);
return promise;
}
}
5.3 离线缓存 #
typescript
// src/services/offline-cache.ts
import { Preferences } from '@capacitor/preferences';
export class OfflineCache {
private static prefix = 'offline_';
static async set(key: string, data: any): Promise<void> {
await Preferences.set({
key: `${this.prefix}${key}`,
value: JSON.stringify({
data,
timestamp: Date.now()
})
});
}
static async get<T>(key: string, maxAge?: number): Promise<T | null> {
const { value } = await Preferences.get({
key: `${this.prefix}${key}`
});
if (!value) return null;
const cached = JSON.parse(value);
if (maxAge && Date.now() - cached.timestamp > maxAge) {
return null;
}
return cached.data;
}
static async getOrFetch<T>(key: string, fetcher: () => Promise<T>, maxAge?: number): Promise<T> {
const cached = await this.get<T>(key, maxAge);
if (cached !== null) {
return cached;
}
const data = await fetcher();
await this.set(key, data);
return data;
}
}
六、打包优化 #
6.1 Vite配置优化 #
typescript
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
react(),
visualizer({ open: false })
],
build: {
// 启用压缩
minify: 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
// 代码分割
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom'],
'vendor-router': ['react-router-dom'],
'vendor-utils': ['lodash-es', 'date-fns']
}
}
},
// 启用gzip压缩报告
reportCompressedSize: true,
// chunk大小警告阈值
chunkSizeWarningLimit: 500
},
// 优化依赖预构建
optimizeDeps: {
include: ['react', 'react-dom', 'react-router-dom']
}
});
6.2 资源优化 #
typescript
// 图片压缩配置
// vite.config.ts
import viteImagemin from 'vite-plugin-imagemin';
export default defineConfig({
plugins: [
viteImagemin({
gifsicle: { optimizationLevel: 3 },
optipng: { optimizationLevel: 7 },
mozjpeg: { quality: 80 },
svgo: {
plugins: [
{ name: 'removeViewBox', active: false }
]
}
})
]
});
6.3 分析打包结果 #
bash
# 安装分析工具
npm install rollup-plugin-visualizer -D
# 构建后查看分析报告
npm run build
七、性能测试 #
7.1 Lighthouse测试 #
bash
# 安装Lighthouse
npm install -g lighthouse
# 运行测试
lighthouse https://your-app.com --view
7.2 性能基准测试 #
typescript
// src/tests/performance.test.ts
describe('Performance Tests', () => {
it('should load within 3 seconds', async () => {
const start = performance.now();
await page.goto('https://your-app.com');
await page.waitForSelector('#app');
const duration = performance.now() - start;
expect(duration).toBeLessThan(3000);
});
it('should have no memory leaks', async () => {
const initialMemory = await getMemoryUsage();
// 执行操作
for (let i = 0; i < 100; i++) {
await page.click('#add-item');
}
const finalMemory = await getMemoryUsage();
expect(finalMemory - initialMemory).toBeLessThan(50 * 1024 * 1024);
});
});
八、最佳实践总结 #
8.1 优化清单 #
| 阶段 | 优化项 |
|---|---|
| 启动 | 延迟加载、代码分割、预加载 |
| 运行时 | 内存管理、缓存策略 |
| 网络 | 请求优化、离线缓存 |
| 打包 | 代码压缩、资源优化 |
8.2 持续优化 #
- 定期进行性能测试
- 监控生产环境性能
- 收集用户反馈
- 持续改进优化
8.3 下一步 #
了解性能优化后,让我们学习 电商应用实战!
最后更新:2026-03-28