Fix memory leak: throttle streaming updates, remove console.logs

This commit is contained in:
Alexej Wolff
2026-05-04 01:13:28 +02:00
parent ad2d27412f
commit 302b56bd5f
2 changed files with 28 additions and 39 deletions
+28 -26
View File
@@ -1,4 +1,4 @@
import { useState, useEffect, useRef } from "react";
import { useState, useEffect, useRef, useCallback } from "react";
import { useParams, Link, useSearchParams } from "react-router-dom";
import ReactMarkdown from "react-markdown";
import { useAuth } from "../contexts/AuthContext";
@@ -69,6 +69,26 @@ export default function GamePage() {
const messagesEndRef = useRef<HTMLDivElement>(null);
const messagesContainerRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLTextAreaElement>(null);
// Refs for throttled streaming updates
const streamingBufferRef = useRef("");
const lastUpdateRef = useRef(0);
// Throttled streaming update (every 50ms instead of every chunk)
const updateStreamingContent = useCallback((chunk: string) => {
streamingBufferRef.current += chunk;
const now = Date.now();
if (now - lastUpdateRef.current > 50) {
setStreamingContent(streamingBufferRef.current);
lastUpdateRef.current = now;
}
}, []);
// Flush remaining content
const flushStreamingContent = useCallback(() => {
if (streamingBufferRef.current) {
setStreamingContent(streamingBufferRef.current);
}
}, []);
useEffect(() => {
const loadGame = async () => {
@@ -87,7 +107,6 @@ export default function GamePage() {
// Загружаем список сессий
const sessions = await getSessionsList(id);
console.log("[GamePage] Sessions list:", sessions);
setSessionsList(sessions);
const characterId = searchParams.get("character");
@@ -109,10 +128,8 @@ export default function GamePage() {
// Если есть сессии, загружаем последнюю (или создаём новую)
if (sessions.length > 0) {
const latestSession = sessions[0];
console.log("[GamePage] Loading latest session:", latestSession);
setCurrentSessionId(latestSession.id);
const sessionData = await getSession(id, latestSession.id);
console.log("[GamePage] Session data loaded:", sessionData);
if (sessionData) {
setSession(sessionData);
// Загружаем персонажа: приоритет URL > сессия
@@ -170,7 +187,6 @@ export default function GamePage() {
id: (updatedStory as any)._id || updatedStory.id,
};
setStory(normalizedStory);
console.log("[GamePage] История обновлена после возврата на страницу");
}
};
@@ -285,6 +301,7 @@ export default function GamePage() {
setIsLoading(true);
setError(null);
setStreamingContent("");
streamingBufferRef.current = "";
// Создаём AbortController для возможности отмены
abortControllerRef.current = new AbortController();
@@ -295,13 +312,12 @@ export default function GamePage() {
story,
session.messages,
input.trim(),
(chunk) => {
setStreamingContent((prev) => prev + chunk);
},
updateStreamingContent,
playerCharacter || undefined,
session,
abortControllerRef.current.signal,
);
flushStreamingContent();
const assistantMessage: ChatMessage = {
id: generateId(),
@@ -321,7 +337,6 @@ export default function GamePage() {
// Генерируем сводку каждые 20 сообщений
let newSummary = session.storySummary;
if (allMessages.length % 20 === 0 && allMessages.length > 0) {
console.log("[GamePage] Generating story summary...");
newSummary = await generateStorySummary(
story,
allMessages,
@@ -336,17 +351,11 @@ export default function GamePage() {
storySummary: newSummary,
};
const saved = await apiSaveSession(
await apiSaveSession(
story.id,
currentSessionId,
finalSession,
);
console.log(
"[GamePage] Session saved:",
saved,
"Messages:",
allMessages.length,
);
setSession(finalSession);
} catch (err) {
if (err instanceof Error && err.name === "AbortError") {
@@ -466,6 +475,7 @@ export default function GamePage() {
setIsLoading(true);
setError(null);
setStreamingContent("");
streamingBufferRef.current = "";
abortControllerRef.current = new AbortController();
@@ -475,13 +485,12 @@ export default function GamePage() {
story,
messagesUpToEdit,
editContent.trim(),
(chunk) => {
setStreamingContent((prev) => prev + chunk);
},
updateStreamingContent,
playerCharacter || undefined,
session,
abortControllerRef.current.signal,
);
flushStreamingContent();
// Сохраняем ответ ИИ в текущую версию
const finalVersions: MessageVersion[] = [...newVersions];
@@ -653,12 +662,6 @@ export default function GamePage() {
};
const handleSwitchSession = async (sessionId: string) => {
console.log(
"[GamePage] Switching to session:",
sessionId,
"current:",
currentSessionId,
);
if (!id || sessionId === currentSessionId) {
setShowSessionMenu(false);
return;
@@ -668,7 +671,6 @@ export default function GamePage() {
setIsInitialLoading(true);
const sessionData = await getSession(id, sessionId);
console.log("[GamePage] Loaded session data:", sessionData);
if (sessionData) {
setCurrentSessionId(sessionId);
setSession(sessionData);