性能优化 #

一、性能概述 #

1.1 性能指标 #

指标 目标 说明
启动时间 < 1s 应用启动到可交互
内存占用 < 100MB 正常使用时内存
CPU 占用 < 5% 空闲时 CPU
包体积 < 10MB 安装包大小

1.2 性能瓶颈 #

text
┌─────────────────────────────────────────────────────────────┐
│                      性能瓶颈分析                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  启动阶段                                                   │
│  ├── Rust 编译产物加载                                      │
│  ├── WebView 初始化                                         │
│  └── 前端资源加载                                           │
│                                                             │
│  运行阶段                                                   │
│  ├── IPC 通信开销                                           │
│  ├── DOM 渲染                                               │
│  └── JavaScript 执行                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

二、启动优化 #

2.1 延迟加载 #

rust
use tauri::Manager;

tauri::Builder::default()
    .setup(|app| {
        // 只初始化必要模块
        let handle = app.handle().clone();
        
        // 延迟加载非必要模块
        std::thread::spawn(move || {
            // 后台初始化
            initialize_plugins(&handle);
        });
        
        Ok(())
    })
    .run(tauri::generate_context!())
    .expect("error while running tauri application");

2.2 前端代码分割 #

typescript
// 路由懒加载
import { lazy, Suspense } from 'react';

const Settings = lazy(() => import('./pages/Settings'));
const About = lazy(() => import('./pages/About'));

function App() {
    return (
        <Suspense fallback={<div>Loading...</div>}>
            <Routes>
                <Route path="/settings" element={<Settings />} />
                <Route path="/about" element={<About />} />
            </Routes>
        </Suspense>
    );
}

2.3 资源预加载 #

html
<!-- 预加载关键资源 -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/css/main.css" as="style">

2.4 减少依赖 #

toml
# Cargo.toml
[dependencies]
# 只启用需要的 features
tauri = { version = "2", default-features = false, features = ["tray-icon"] }

三、运行时优化 #

3.1 减少 IPC 调用 #

typescript
// ❌ 多次 IPC 调用
async function loadUserData() {
    const name = await invoke('get_user_name');
    const email = await invoke('get_user_email');
    const avatar = await invoke('get_user_avatar');
}

// ✅ 单次 IPC 调用
async function loadUserData() {
    const user = await invoke('get_user');
    return user;
}

3.2 批量操作 #

rust
// ❌ 多次调用
#[tauri::command]
fn get_item(id: u32) -> Item { /* ... */ }

// ✅ 批量获取
#[tauri::command]
fn get_items(ids: Vec<u32>) -> Vec<Item> {
    ids.into_iter().map(|id| fetch_item(id)).collect()
}

3.3 使用缓存 #

rust
use std::collections::HashMap;
use std::sync::Mutex;
use std::time::{Duration, Instant};

struct Cache<T> {
    data: HashMap<String, (T, Instant)>,
    ttl: Duration,
}

impl<T: Clone> Cache<T> {
    fn get(&self, key: &str) -> Option<T> {
        self.data.get(key)
            .filter(|(_, time)| time.elapsed() < self.ttl)
            .map(|(data, _)| data.clone())
    }
    
    fn set(&mut self, key: String, value: T) {
        self.data.insert(key, (value, Instant::now()));
    }
}

3.4 虚拟列表 #

tsx
import { FixedSizeList } from 'react-window';

function VirtualList({ items }: { items: string[] }) {
    return (
        <FixedSizeList
            height={400}
            width={300}
            itemCount={items.length}
            itemSize={35}
        >
            {({ index, style }) => (
                <div style={style}>{items[index]}</div>
            )}
        </FixedSizeList>
    );
}

四、内存优化 #

4.1 及时释放资源 #

rust
#[tauri::command]
fn process_large_file(path: String) -> Result<(), String> {
    // 使用作用域自动释放
    {
        let content = std::fs::read_to_string(&path)
            .map_err(|e| e.to_string())?;
        
        process_content(&content);
    } // content 在这里被释放
    
    Ok(())
}

4.2 流式处理 #

rust
use std::io::{BufRead, BufReader};
use std::fs::File;

#[tauri::command]
fn process_large_file_stream(path: String) -> Result<u64, String> {
    let file = File::open(&path).map_err(|e| e.to_string())?;
    let reader = BufReader::new(file);
    
    let mut count = 0;
    for line in reader.lines() {
        let line = line.map_err(|e| e.to_string())?;
        if !line.is_empty() {
            count += 1;
        }
    }
    
    Ok(count)
}

4.3 避免内存泄漏 #

typescript
// 清理事件监听
useEffect(() => {
    const unlisten = listen('event', handler);
    
    return () => {
        unlisten.then(fn => fn());
    };
}, []);

// 清理定时器
useEffect(() => {
    const timer = setInterval(() => {}, 1000);
    
    return () => {
        clearInterval(timer);
    };
}, []);

五、包体积优化 #

5.1 Rust 编译优化 #

toml
# Cargo.toml
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
opt-level = "s"
strip = true

[profile.release.package."*"]
opt-level = "s"

5.2 前端构建优化 #

typescript
// vite.config.ts
export default defineConfig({
    build: {
        minify: 'esbuild',
        target: ['es2021'],
        rollupOptions: {
            output: {
                manualChunks: {
                    vendor: ['react', 'react-dom'],
                    tauri: ['@tauri-apps/api'],
                },
            },
        },
    },
});

5.3 移除未使用代码 #

typescript
// package.json
{
    "sideEffects": false
}

5.4 压缩资源 #

typescript
// vite.config.ts
import viteImagemin from 'vite-plugin-imagemin';

export default defineConfig({
    plugins: [
        viteImagemin({
            gifsicle: { optimizationLevel: 3 },
            optipng: { optimizationLevel: 7 },
            mozjpeg: { quality: 80 },
        }),
    ],
});

六、网络优化 #

6.1 请求合并 #

typescript
// ❌ 多次请求
async function loadData() {
    const user = await fetch('/api/user');
    const posts = await fetch('/api/posts');
    const comments = await fetch('/api/comments');
}

// ✅ 并行请求
async function loadData() {
    const [user, posts, comments] = await Promise.all([
        fetch('/api/user'),
        fetch('/api/posts'),
        fetch('/api/comments'),
    ]);
}

6.2 数据压缩 #

rust
use flate2::write::GzEncoder;
use flate2::Compression;

#[tauri::command]
fn compress_data(data: String) -> Vec<u8> {
    let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
    encoder.write_all(data.as_bytes()).unwrap();
    encoder.finish().unwrap()
}

七、监控与分析 #

7.1 性能监控 #

typescript
// 使用 Performance API
const start = performance.now();
await heavyOperation();
const end = performance.now();
console.log(`Operation took ${end - start}ms`);

7.2 Rust 性能分析 #

bash
# 使用 cargo flamegraph
cargo install flamegraph
cargo flamegraph --root

# 使用 cargo bench
cargo bench

7.3 内存分析 #

bash
# 使用 valgrind (Linux)
valgrind --leak-check=full ./myapp

# 使用 Instruments (macOS)
instruments -t Leaks ./myapp

八、最佳实践 #

8.1 性能检查清单 #

markdown
## 启动性能
- [ ] 延迟加载非必要模块
- [ ] 代码分割
- [ ] 资源预加载
- [ ] 减少依赖

## 运行时性能
- [ ] 减少 IPC 调用
- [ ] 使用缓存
- [ ] 虚拟列表
- [ ] 防抖节流

## 内存优化
- [ ] 及时释放资源
- [ ] 流式处理大文件
- [ ] 清理事件监听
- [ ] 避免内存泄漏

## 包体积
- [ ] 编译优化
- [ ] Tree shaking
- [ ] 资源压缩
- [ ] 移除未使用代码

8.2 性能测试 #

typescript
// 性能测试工具
async function measurePerformance(name: string, fn: () => Promise<void>) {
    const start = performance.now();
    await fn();
    const end = performance.now();
    console.log(`${name}: ${end - start}ms`);
}

// 使用
await measurePerformance('loadData', async () => {
    await loadData();
});

九、总结 #

9.1 核心要点 #

要点 说明
启动优化 延迟加载、代码分割
运行时优化 减少 IPC、缓存、虚拟列表
内存优化 及时释放、流式处理
包体积 编译优化、Tree shaking
监控分析 性能监控、内存分析

9.2 下一步 #

现在你已经掌握了性能优化,接下来让我们学习 调试技巧,了解 Tauri 应用的调试方法!

最后更新:2026-03-28