refactor(Index.tsx): introduce AbortController for debounced text correction to prevent race conditions

This commit is contained in:
2025-08-29 18:29:47 +02:00
parent bed316c17a
commit 70f1bf8c35

View File

@@ -121,9 +121,9 @@ Keep tags concise, use lowercase, and separate words with hyphens if needed.`);
$current`);
const [contextSize, setContextSize] = useState(3);
const [correctedContent, setCorrectedContent] = useState('');
const [previousNoteCorrectedContent, setPreviousNoteCorrectedContent] = useState('');
const [correctionTimeout, setCorrectionTimeout] = useState<NodeJS.Timeout>();
const [correctionAbortController, setCorrectionAbortController] = useState<AbortController | null>(null);
const { resolvedTheme, setTheme } = useTheme();
@@ -312,49 +312,41 @@ $current`);
setTagGenerationTimeout(timeout);
};
// Debounced text correction for current note
const debouncedCorrectText = (content: string) => {
if (correctionTimeout) {
clearTimeout(correctionTimeout);
}
const timeout = setTimeout(async () => {
if (content.trim()) {
try {
addDebugInfo('Correcting current note text...');
const corrected = await correctText(content);
setCorrectedContent(corrected);
} catch (error) {
console.error('Text correction failed:', error);
setCorrectedContent('');
}
} else {
setCorrectedContent('');
}
}, 500);
setCorrectionTimeout(timeout);
};
// Debounced text correction for previous note
const debouncedCorrectPreviousNote = (content: string) => {
// Cancel any pending correction request IMMEDIATELY
if (correctionAbortController) {
correctionAbortController.abort();
}
if (correctionTimeout) {
clearTimeout(correctionTimeout);
}
// Create new AbortController for this request
const abortController = new AbortController();
setCorrectionAbortController(abortController);
const timeout = setTimeout(async () => {
if (content.trim()) {
try {
addDebugInfo('Correcting previous note text...');
const corrected = await correctText(content);
const corrected = await correctText(content, abortController);
addDebugInfo(`Received correction: ${corrected.substring(0, 50)}...`);
setPreviousNoteCorrectedContent(corrected);
addDebugInfo('Previous note corrected content set');
} catch (error) {
if (error instanceof Error && error.name === 'AbortError') {
addDebugInfo('Previous note correction cancelled');
return; // Don't set empty content for aborted requests
} else {
console.error('Previous note text correction failed:', error);
addDebugInfo(`Correction error: ${error instanceof Error ? error.message : 'Unknown error'}`);
setPreviousNoteCorrectedContent('');
}
}
} else {
setPreviousNoteCorrectedContent('');
}
@@ -364,7 +356,7 @@ $current`);
};
// Correct text using Ollama
const correctText = async (content: string): Promise<string> => {
const correctText = async (content: string, abortController?: AbortController): Promise<string> => {
try {
const response = await fetchWithTiming(`${ollamaEndpoint}/api/generate`, {
method: 'POST',
@@ -390,6 +382,7 @@ ${content}`,
keep_alive: ollamaKeepAlive,
temperature: 0.1,
}),
signal: abortController?.signal,
}, 'Correct Text');
if (!response.ok) {
@@ -1172,6 +1165,12 @@ ${content}`,
const reversedDelta = -delta;
const newIndex = Math.max(0, Math.min(currentNoteIndex + reversedDelta, noteCache.length - 1));
if (newIndex !== currentNoteIndex && noteCache[newIndex]) {
// CANCEL THE FUCKING REQUEST IMMEDIATELY
if (correctionAbortController) {
correctionAbortController.abort();
setCorrectionAbortController(null);
}
setCurrentNoteIndex(newIndex);
setPreviousNote(noteCache[newIndex]);
setIsPreviousNoteModified(false);
@@ -1364,7 +1363,10 @@ ${content}`,
if (correctionTimeout) {
clearTimeout(correctionTimeout);
}
// Cleanup complete
// Cancel any pending correction request on cleanup
if (correctionAbortController) {
correctionAbortController.abort();
}
};
}, [currentNote, previousNote, scratchPad, isPreviousNoteModified, isSearchOpen, isGotoOpen, isCleanupOpen]);