# 应用启动预加载优化 ## 概述 为了提升用户体验,避免"先有鸡还是先有蛋"的问题,应用在启动时会自动加载所有必要的配置数据。 ## 预加载的数据 ### 1. API 配置 ✅ **为什么需要预加载:** - 聊天功能依赖 API 配置才能调用 LLM - 用户可能直接开始聊天而不访问 API 配置页面 **加载逻辑:** ```javascript // 1. 加载配置文件列表 await apiConfigStore.fetchProfiles(); // 2. 如果有配置但没有选中,自动加载第一个 if (profiles.length > 0 && !currentProfile) { await fetchProfile(profiles[0].id); } ``` **日志输出:** ``` [App] ✅ API 配置文件列表加载完成 [App] 📝 自动加载第一个配置文件: Default [App] ✅ API 配置详情加载完成 ``` ### 2. 预设列表 ✅ **为什么需要预加载:** - 聊天时使用预设中的参数(temperature、max_tokens 等) - 提示词组件来自预设配置 **加载逻辑:** ```javascript // 1. 加载预设列表 await presetStore.fetchPresets(); // 2. 如果没有选中预设,自动选择第一个 if (!selectedPreset && presets.length > 0) { selectPreset(presets[0].name); } ``` **日志输出:** ``` [App] ✅ 预设列表加载完成 [App] 📝 自动选择第一个预设: Default ``` ### 3. 角色卡列表 ✅ **为什么需要预加载:** - 用户打开应用后需要立即看到可用的角色 - 避免切换到角色卡标签页时才加载的延迟 **加载逻辑:** ```javascript await characterStore.fetchCharacters(); ``` **日志输出:** ``` [App] ✅ 角色卡列表加载完成 ``` ### 4. 世界书列表 ✅ **为什么需要预加载:** - 角色卡可能绑定世界书 - 聊天时需要激活世界书条目 **加载逻辑:** ```javascript await worldBookStore.fetchWorldBooks(); ``` **日志输出:** ``` [App] ✅ 世界书列表加载完成 ``` ## 不需要预加载的数据 ### Token 使用统计 ❌ **原因:** - 这是查看型数据,不是必需的配置 - 数据量可能较大 - 用户不一定需要查看 **加载时机:** - 用户切换到 Token 使用标签页时再加载 ### 任务列表 ❌ **原因:** - 任务是动态生成的 - 每次聊天时根据选项创建 - 不需要持久化 **加载时机:** - 聊天时根据需要创建 ### 正则规则 ❌ **原因:** - 使用时才加载 - 可能按角色或预设分别加载 **加载时机:** - 处理消息时按需加载 ## 技术实现 ### 并行加载 使用 `Promise.allSettled` 并行加载所有数据,而不是串行: ```javascript Promise.allSettled([ loadApiConfig(), loadPresets(), loadCharacters(), loadWorldBooks() ]).then((results) => { // 处理结果 }); ``` **优势:** - ⚡ 速度更快:4个请求同时发起,总时间 ≈ 最慢的那个请求 - 🛡️ 容错性强:单个失败不影响其他数据加载 - 📊 可统计:知道哪些成功、哪些失败 ### 错误处理 每个加载任务都有独立的 try-catch: ```javascript (async () => { try { await fetchData(); console.log('✅ 加载成功'); } catch (err) { console.error('❌ 加载失败:', err); } })() ``` **优势:** - 单个数据源失败不会中断其他加载 - 详细的错误日志便于调试 - 应用仍可正常使用(降级处理) ### 性能监控 记录加载耗时: ```javascript const startTime = Date.now(); // ... 加载数据 ... const duration = ((Date.now() - startTime) / 1000).toFixed(2); console.log(`[App] 🎉 配置加载完成 (${duration}s)`); ``` **日志输出:** ``` [App] 🎉 配置加载完成 (1.23s) [App] 📊 成功: 4, 失败: 0 ``` ## 用户体验提升 ### Before(优化前) ``` 用户操作流程: 1. 打开应用 2. 点击左侧边栏 → API 配置 3. 等待加载配置文件 4. 选择/创建配置 5. 点击左侧边栏 → 预设 6. 等待加载预设列表 7. 选择预设 8. 点击左侧边栏 → 角色卡 9. 等待加载角色列表 10. 选择角色 11. 开始聊天 总耗时:~5-10秒(多次等待) ``` ### After(优化后) ``` 用户操作流程: 1. 打开应用(后台自动加载所有配置) 2. 等待 ~1-2秒(并行加载) 3. 直接选择角色开始聊天 总耗时:~1-2秒(一次等待) ``` **提升:** - ⏱️ 减少等待时间 60-80% - 🎯 操作步骤减少 7步 → 2步 - 😊 用户体验更流畅 ## 日志示例 ### 成功情况 ``` [App] 🚀 应用启动,开始加载默认配置... [App] ✅ API 配置文件列表加载完成 [App] 📝 自动加载第一个配置文件: Default [App] ✅ API 配置详情加载完成 [App] ✅ 预设列表加载完成 [App] 📝 自动选择第一个预设: Default [App] ✅ 角色卡列表加载完成 [App] ✅ 世界书列表加载完成 [App] 🎉 配置加载完成 (1.23s) [App] 📊 成功: 4, 失败: 0 ``` ### 部分失败情况 ``` [App] 🚀 应用启动,开始加载默认配置... [App] ✅ API 配置文件列表加载完成 [App] ✅ 预设列表加载完成 [App] 📝 自动选择第一个预设: Default [App] ✅ 角色卡列表加载完成 [App] ❌ 世界书列表加载失败: Network error [App] 🎉 配置加载完成 (2.45s) [App] 📊 成功: 3, 失败: 1 [App] ⚠️ 部分配置加载失败,但应用仍可正常使用 ``` ### 没有配置的情况 ``` [App] 🚀 应用启动,开始加载默认配置... [App] ✅ API 配置文件列表加载完成 [App] ⚠️ 没有可用的 API 配置文件,请先到 API 配置页面创建 [App] ✅ 预设列表加载完成 [App] ⚠️ 没有可用的预设 [App] ✅ 角色卡列表加载完成 [App] ✅ 世界书列表加载完成 [App] 🎉 配置加载完成 (0.89s) [App] 📊 成功: 4, 失败: 0 ``` ## 最佳实践 ### 1. 只预加载必要的数据 **应该预加载:** - ✅ 应用运行必需的配置 - ✅ 用户首次操作就需要看到的数据 - ✅ 数据量小、加载快的内容 **不应该预加载:** - ❌ 查看型数据(统计、历史等) - ❌ 大数据量的内容 - ❌ 用户可能不需要的功能 ### 2. 并行而非串行 ```javascript // ❌ 错误:串行加载,总时间 = 所有请求时间之和 await loadA(); await loadB(); await loadC(); // ✅ 正确:并行加载,总时间 ≈ 最慢的请求 await Promise.allSettled([ loadA(), loadB(), loadC() ]); ``` ### 3. 容错处理 ```javascript // ❌ 错误:一个失败全部中断 await Promise.all([loadA(), loadB(), loadC()]); // ✅ 正确:单个失败不影响其他 await Promise.allSettled([loadA(), loadB(), loadC()]); ``` ### 4. 详细日志 ```javascript // ❌ 错误:没有日志,无法调试 await fetchData(); // ✅ 正确:清晰的日志输出 console.log('[App] 🚀 开始加载...'); try { await fetchData(); console.log('[App] ✅ 加载成功'); } catch (err) { console.error('[App] ❌ 加载失败:', err); } ``` ### 5. 性能监控 ```javascript const startTime = Date.now(); await loadData(); const duration = Date.now() - startTime; console.log(`加载耗时: ${duration}ms`); ``` ## 未来优化方向 ### 1. 缓存策略 ```javascript // 检查是否有缓存数据 const cached = localStorage.getItem('apiConfig'); if (cached) { // 使用缓存,后台静默更新 useCache(cached); fetchAndUpdateInBackground(); } else { // 没有缓存,正常加载 await fetchData(); } ``` ### 2. 懒加载非关键数据 ```javascript // 关键数据:立即加载 await loadCriticalData(); // 非关键数据:空闲时加载 requestIdleCallback(() => { loadNonCriticalData(); }); ``` ### 3. 预取用户可能需要的数据 ```javascript // 用户选择了角色,预取该角色的聊天历史 selectCharacter(char => { preloadChatHistory(char.id); }); ``` ## 总结 通过应用启动时预加载必要配置: ✅ **用户体验提升** - 减少等待时间 60-80% - 操作步骤大幅简化 - 无需手动切换页面配置 ✅ **技术优势** - 并行加载,速度更快 - 容错性强,单个失败不影响整体 - 详细日志,便于调试 ✅ **代码质量** - 清晰的加载逻辑 - 完善的错误处理 - 性能监控和统计 这种优化让应用更加"开箱即用",用户打开即可开始使用,无需繁琐的初始配置步骤。