fix: fix memory leaking in Chat.svelte (#21962)

* fix: fix memory leaking in Chat.svelte

* chore: remove useless chatIdUnsubscriber var

* fix: fix async tick
This commit is contained in:
Shirasawa
2026-03-01 15:04:47 -05:00
committed by GitHub
parent 2054ee0b73
commit 9904566513
2 changed files with 69 additions and 66 deletions
+67 -65
View File
@@ -110,10 +110,10 @@
let loading = true;
const eventTarget = new EventTarget();
let controlPane;
let controlPaneComponent;
let controlPane: Pane | undefined;
let controlPaneComponent: ChatControls | undefined;
let messageInput;
let messageInput: MessageInput | undefined;
let autoScroll = true;
let processing = '';
@@ -130,8 +130,6 @@
let eventConfirmationInputType = '';
let eventCallback = null;
let chatIdUnsubscriber: Unsubscriber | undefined;
let selectedModels = [''];
let atSelectedModel: Model | undefined;
let selectedModelIds = [];
@@ -657,24 +655,23 @@
savedModelIds();
}
let pageSubscribe = null;
let showControlsSubscribe = null;
let selectedFolderSubscribe = null;
const stopAudio = () => {
try {
speechSynthesis.cancel();
$audioQueue.stop();
$audioQueue?.stop();
} catch {}
};
onMount(async () => {
onMount(() => {
loading = true;
console.log('mounted');
window.addEventListener('message', onMessageHandler);
$socket?.on('events', chatEventHandler);
audioQueue.set(new AudioQueue(document.getElementById('audioElement')));
$audioQueue?.destroy();
const audioQueueInstance = new AudioQueue(document.getElementById('audioElement'));
audioQueue.set(audioQueueInstance);
// Reset direct terminal enabled states — selectedTerminalId starts null on every page load
if ($settings?.terminalServers?.some((s) => s.enabled)) {
@@ -684,7 +681,7 @@
});
}
pageSubscribe = page.subscribe(async (p) => {
const pageSubscribe = page.subscribe(async (p) => {
if (p.url.pathname === '/') {
await tick();
initNewChat();
@@ -693,46 +690,12 @@
stopAudio();
});
const storageChatInput = sessionStorage.getItem(
`chat-input${chatIdProp ? `-${chatIdProp}` : ''}`
);
if (!chatIdProp) {
loading = false;
const showControlsSubscribe = showControls.subscribe(async (value) => {
await tick();
}
if (storageChatInput) {
prompt = '';
messageInput?.setText('');
files = [];
selectedToolIds = [];
selectedFilterIds = [];
webSearchEnabled = false;
imageGenerationEnabled = false;
codeInterpreterEnabled = false;
try {
const input = JSON.parse(storageChatInput);
if (!$temporaryChatEnabled) {
messageInput?.setText(input.prompt);
files = input.files;
selectedToolIds = input.selectedToolIds;
selectedFilterIds = input.selectedFilterIds;
webSearchEnabled = input.webSearchEnabled;
imageGenerationEnabled = input.imageGenerationEnabled;
codeInterpreterEnabled = input.codeInterpreterEnabled;
}
} catch (e) {}
}
showControlsSubscribe = showControls.subscribe(async (value) => {
if (controlPane && !$mobile) {
try {
if (value) {
controlPaneComponent.openPane();
controlPaneComponent?.openPane();
} else {
controlPane.collapse();
}
@@ -748,7 +711,8 @@
}
});
selectedFolderSubscribe = selectedFolder.subscribe(async (folder) => {
const selectedFolderSubscribe = selectedFolder.subscribe(async (folder) => {
await tick();
if (
folder?.data?.model_ids &&
JSON.stringify(selectedModels) !== JSON.stringify(folder.data.model_ids)
@@ -759,22 +723,60 @@
}
});
const chatInput = document.getElementById('chat-input');
chatInput?.focus();
});
const storageChatInput = sessionStorage.getItem(
`chat-input${chatIdProp ? `-${chatIdProp}` : ''}`
);
onDestroy(() => {
try {
pageSubscribe();
showControlsSubscribe();
selectedFolderSubscribe();
chatIdUnsubscriber?.();
window.removeEventListener('message', onMessageHandler);
$socket?.off('events', chatEventHandler);
$audioQueue?.destroy();
} catch (e) {
console.error(e);
}
const init = async () => {
if (!chatIdProp) {
loading = false;
await tick();
}
if (storageChatInput) {
prompt = '';
messageInput?.setText('');
files = [];
selectedToolIds = [];
selectedFilterIds = [];
webSearchEnabled = false;
imageGenerationEnabled = false;
codeInterpreterEnabled = false;
try {
const input = JSON.parse(storageChatInput);
if (!$temporaryChatEnabled) {
messageInput?.setText(input.prompt);
files = input.files;
selectedToolIds = input.selectedToolIds;
selectedFilterIds = input.selectedFilterIds;
webSearchEnabled = input.webSearchEnabled;
imageGenerationEnabled = input.imageGenerationEnabled;
codeInterpreterEnabled = input.codeInterpreterEnabled;
}
} catch (e) {}
}
const chatInput = document.getElementById('chat-input');
chatInput?.focus();
};
init();
return () => {
try {
pageSubscribe();
showControlsSubscribe();
selectedFolderSubscribe();
window.removeEventListener('message', onMessageHandler);
$socket?.off('events', chatEventHandler);
audioQueueInstance?.destroy();
audioQueue.set(null);
} catch (e) {
console.error(e);
}
};
});
// File upload functions
+2 -1
View File
@@ -3,6 +3,7 @@ import { type Writable, writable } from 'svelte/store';
import type { ModelConfig } from '$lib/apis';
import type { Banner } from '$lib/types';
import type { Socket } from 'socket.io-client';
import type { AudioQueue } from '$lib/utils/audio';
import emojiShortCodes from '$lib/emoji-shortcodes.json';
@@ -75,7 +76,7 @@ export const banners: Writable<Banner[]> = writable([]);
export const settings: Writable<Settings> = writable({});
export const audioQueue = writable(null);
export const audioQueue = writable<AudioQueue | null>(null);
export const sidebarWidth = writable(260);