修复: CR-24 AiChat listener 泄漏(stopListener 接入 onBeforeUnmount+补 clearStreamWatchdog)

useAiEvents stopListener 补 clearStreamWatchdog()(原漏清 _streamWatchdog 计时器,卸载后 130s onStreamTimeout 仍写 state);AiChat onBeforeUnmount 补 store.stopListener()(原全仓零调用 listener+watchdog 永久泄漏)。R1 双注册经核查 App.vue:94 v-if 互斥(detach 卸载主窗口 AiChat)同一时刻仅一窗口持活 listener,无真实双消费,不加去重标志避免过度防御(留后续:互斥逻辑改变则需去重或后端 emit_to 定向)。批8 wsyxw19ai,vue-tsc 0
This commit is contained in:
2026-06-15 08:21:11 +08:00
parent 16aeacc37b
commit ef2d033ad6
2 changed files with 8 additions and 1 deletions

View File

@@ -746,6 +746,10 @@ watch(() => store.state.streaming, (s) => {
})
onBeforeUnmount(() => {
if (rafId !== null) cancelAnimationFrame(rafId)
// CR-260615-24: 释放后端 listener(ai-chat-event/ai-conversation-changed)+清流式看门狗。
// 之前 stopListener 定义但全仓零调用 → listener+watchdog 永久泄漏;分离窗口主窗口 AiChat
// 卸载(走 App.vue v-if detach)时 listener 仍挂后端,watchdog 130s 后写已卸载 state。
store.stopListener()
})
// ── 工具卡片自动收起:新内容追加(新消息/toolCall 状态变化/文本增长)时,

View File

@@ -254,12 +254,15 @@ export async function startListener() {
}
}
/** 停止事件监听(卸载时调用,释放后端 listener) */
/** 停止事件监听(卸载时调用,释放后端 listener + 清看门狗)
* 清看门狗:卸载时若仍在生成,_streamWatchdog 计时器未释放,130s 后 onStreamTimeout
* 仍写 state(messages.push/置 streaming)——已卸载组件不应再被触发。故同步清除。 */
function stopListener() {
_unlistenAiEvent?.()
_unlistenConvChanged?.()
_unlistenAiEvent = null
_unlistenConvChanged = null
clearStreamWatchdog()
}
export function useAiEvents() {