性能优化 #

一、性能指标 #

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