Files
SillyTavern_replica/APP_INITIALIZATION_OPTIMIZATION.md

382 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 应用启动预加载优化
## 概述
为了提升用户体验,避免"先有鸡还是先有蛋"的问题,应用在启动时会自动加载所有必要的配置数据。
## 预加载的数据
### 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%
- 操作步骤大幅简化
- 无需手动切换页面配置
**技术优势**
- 并行加载,速度更快
- 容错性强,单个失败不影响整体
- 详细日志,便于调试
**代码质量**
- 清晰的加载逻辑
- 完善的错误处理
- 性能监控和统计
这种优化让应用更加"开箱即用",用户打开即可开始使用,无需繁琐的初始配置步骤。