203 lines
5.7 KiB
Markdown
203 lines
5.7 KiB
Markdown
# Service Worker PostMessage 日志记录优化
|
||
|
||
## 问题描述
|
||
|
||
之前的实现中,PostMessage 日志记录虽然有 `debugModeEnabled` 开关,但在以下场景中仍然会对应用性能产生影响:
|
||
|
||
1. **主线程消息发送时的日志记录**:即使调试模式未启用,仍然会调用 `logSentMessage()` 函数进行日志记录
|
||
2. **消息日志存储和处理**:日志数组会不断增长(最多 500 条),占用内存
|
||
3. **调试面板关闭后的残留**:从启用调试到禁用调试的过程中,日志没有被及时清空
|
||
|
||
## 解决方案
|
||
|
||
### 1. 完全由调试模式控制日志记录
|
||
|
||
在 `postmessage-logger.ts` 中实现以下改进:
|
||
|
||
```typescript
|
||
// 内部检查函数
|
||
function isDebugModeActive(): boolean {
|
||
return debugModeEnabled;
|
||
}
|
||
|
||
// 改进的调试模式设置
|
||
export function setPostMessageLoggerDebugMode(enabled: boolean): void {
|
||
const wasEnabled = debugModeEnabled;
|
||
debugModeEnabled = enabled;
|
||
|
||
if (!enabled && wasEnabled) {
|
||
// 从启用变为禁用时,立即清空日志,释放内存
|
||
logs.length = 0;
|
||
pendingRequests.clear();
|
||
logIdCounter = 0;
|
||
}
|
||
}
|
||
|
||
// 改进的消息过滤
|
||
function shouldLogMessage(messageType: string): boolean {
|
||
// 调试模式未启用时,立即返回 false,不进行任何记录操作
|
||
if (!isDebugModeActive()) {
|
||
return false;
|
||
}
|
||
return !EXCLUDED_MESSAGE_TYPES.includes(messageType);
|
||
}
|
||
```
|
||
|
||
### 2. 在 Message Bus 中添加调试模式检查
|
||
|
||
在 `message-bus.ts` 中,在调用 `logSentMessage()` 前检查调试模式:
|
||
|
||
```typescript
|
||
import { isPostMessageLoggerDebugMode } from '../postmessage-logger';
|
||
|
||
export function sendToClient(client: Client, message: unknown): void {
|
||
// ...
|
||
|
||
// Only attempt to log if debug mode is enabled
|
||
let logId = '';
|
||
if (isPostMessageLoggerDebugMode()) {
|
||
const messageType = (message as { type?: string })?.type || 'unknown';
|
||
logId = logSentMessage(messageType, message, client.id);
|
||
}
|
||
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### 3. 在 Service Worker 中同步日志控制
|
||
|
||
在 `sw/index.ts` 中,确保接收消息时也受到调试模式的控制:
|
||
|
||
```typescript
|
||
// Handle messages from main thread
|
||
sw.addEventListener('message', (event: ExtendableMessageEvent) => {
|
||
const messageType = event.data?.type || 'unknown';
|
||
const clientId = (event.source as Client)?.id || '';
|
||
|
||
// Log received message only if debug mode is enabled
|
||
let logId = '';
|
||
if (isPostMessageLoggerDebugMode()) {
|
||
logId = logReceivedMessage(messageType, event.data, clientId);
|
||
if (logId && debugModeEnabled) {
|
||
const logs = getAllPostMessageLogs();
|
||
const entry = logs.find(l => l.id === logId);
|
||
if (entry) {
|
||
broadcastPostMessageLog(entry);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ... rest of the handler
|
||
});
|
||
```
|
||
|
||
## 性能影响
|
||
|
||
### 调试模式关闭时
|
||
|
||
- **零日志记录开销**:不调用任何日志记录函数
|
||
- **零内存占用**:日志数组为空
|
||
- **零性能影响**:应用运行不受影响
|
||
|
||
### 调试模式启用时
|
||
|
||
- **完整的日志记录**:所有 PostMessage 都被记录
|
||
- **实时日志广播**:日志实时显示在调试面板
|
||
- **可接受的性能开销**:仅在调试时产生
|
||
|
||
## 调试面板使用
|
||
|
||
### 启用调试模式
|
||
|
||
1. 打开 `http://localhost:7200/sw-debug.html`
|
||
2. 点击 "启用调试" 按钮
|
||
3. 切换到 "PostMessage 日志" 标签
|
||
4. 查看所有主线程与 Service Worker 之间的消息通信
|
||
|
||
### 自动清理
|
||
|
||
当调试模式禁用时,日志会自动清空以释放内存。
|
||
|
||
## 实现细节
|
||
|
||
### 关键导出函数
|
||
|
||
| 函数 | 模块 | 作用 |
|
||
|------|------|------|
|
||
| `setPostMessageLoggerDebugMode(enabled)` | `postmessage-logger.ts` | 设置调试模式 |
|
||
| `isPostMessageLoggerDebugMode()` | `postmessage-logger.ts` | 检查调试模式是否启用 |
|
||
| `logReceivedMessage()` | `postmessage-logger.ts` | 记录接收的消息(需先检查调试模式) |
|
||
| `logSentMessage()` | `postmessage-logger.ts` | 记录发送的消息(需先检查调试模式) |
|
||
| `setDebugMode(enabled)` | `message-bus.ts` | 配置整个消息总线的调试模式 |
|
||
|
||
### 日志流程
|
||
|
||
```
|
||
启用调试模式
|
||
↓
|
||
setMessageSenderDebugMode(true)
|
||
↓
|
||
setDebugMode(true) in message-bus.ts
|
||
↓
|
||
setPostMessageLoggerDebugMode(true)
|
||
↓
|
||
所有 postMessage 都被记录到调试面板
|
||
↓
|
||
禁用调试模式
|
||
↓
|
||
setPostMessageLoggerDebugMode(false)
|
||
↓
|
||
日志数组立即清空,内存释放
|
||
```
|
||
|
||
## 修改的文件
|
||
|
||
1. **apps/web/src/sw/task-queue/postmessage-logger.ts**
|
||
- 添加 `isDebugModeActive()` 内部函数
|
||
- 改进 `setPostMessageLoggerDebugMode()` 逻辑
|
||
- 改进 `shouldLogMessage()` 函数
|
||
|
||
2. **apps/web/src/sw/task-queue/utils/message-bus.ts**
|
||
- 导入 `isPostMessageLoggerDebugMode`
|
||
- 在 `sendToClient()` 中添加调试模式检查
|
||
- 在 `broadcastToAllClients()` 中添加调试模式检查
|
||
|
||
3. **apps/web/src/sw/index.ts**
|
||
- 导入 `isPostMessageLoggerDebugMode`
|
||
- 在消息处理器中添加调试模式检查
|
||
|
||
4. **apps/web/public/sw-debug.html**
|
||
- 更新 PostMessage 日志标签的提示信息
|
||
- 更新控制台日志标签的提示信息
|
||
|
||
## 测试步骤
|
||
|
||
1. **应用不开启调试时**
|
||
- 正常使用应用
|
||
- 性能不受影响
|
||
|
||
2. **启用调试模式**
|
||
- 打开调试面板
|
||
- 启用调试
|
||
- 切换到 PostMessage 日志标签
|
||
- 执行应用操作
|
||
- 观察日志实时显示
|
||
|
||
3. **禁用调试模式**
|
||
- 点击"禁用调试"
|
||
- 检查日志是否清空
|
||
- 确认内存释放
|
||
|
||
## 向后兼容性
|
||
|
||
所有改动都是向后兼容的:
|
||
- 现有的调试面板功能完全保留
|
||
- 调试模式的启用/禁用逻辑不变
|
||
- 只是改进了性能特性
|
||
|
||
## 相关文件
|
||
|
||
- `/apps/web/public/sw-debug.html` - 调试面板界面
|
||
- `/apps/web/public/sw-debug/app.js` - 调试面板应用逻辑
|
||
- `/apps/web/src/sw/index.ts` - Service Worker 入口
|