mirror of
https://github.com/codeaashu/claude-code.git
synced 2026-04-08 22:28:48 +03:00
67 lines
1.8 KiB
TypeScript
67 lines
1.8 KiB
TypeScript
/**
|
|
* Batches streaming token updates via requestAnimationFrame to avoid
|
|
* per-token re-renders. Flushes accumulated text on each animation frame
|
|
* rather than on every chunk, keeping the UI smooth at 60fps during streaming.
|
|
*/
|
|
export class StreamingOptimizer {
|
|
private buffer = "";
|
|
private rafId: number | null = null;
|
|
private onFlush: (text: string) => void;
|
|
private lastFlushTime = 0;
|
|
/** Max ms to wait before forcing a flush regardless of rAF timing */
|
|
private readonly maxDelay: number;
|
|
|
|
constructor(onFlush: (text: string) => void, maxDelay = 50) {
|
|
this.onFlush = onFlush;
|
|
this.maxDelay = maxDelay;
|
|
}
|
|
|
|
push(chunk: string): void {
|
|
this.buffer += chunk;
|
|
|
|
if (this.rafId !== null) return; // rAF already scheduled
|
|
|
|
const now = performance.now();
|
|
const timeSinceLast = now - this.lastFlushTime;
|
|
|
|
if (timeSinceLast >= this.maxDelay) {
|
|
// Flush is overdue — do it synchronously to avoid latency buildup
|
|
this.flush();
|
|
} else {
|
|
this.rafId = requestAnimationFrame(() => {
|
|
this.rafId = null;
|
|
this.flush();
|
|
});
|
|
}
|
|
}
|
|
|
|
flush(): void {
|
|
if (!this.buffer) return;
|
|
const text = this.buffer;
|
|
this.buffer = "";
|
|
this.lastFlushTime = performance.now();
|
|
this.onFlush(text);
|
|
}
|
|
|
|
destroy(): void {
|
|
if (this.rafId !== null) {
|
|
cancelAnimationFrame(this.rafId);
|
|
this.rafId = null;
|
|
}
|
|
// Flush any remaining buffered text
|
|
this.flush();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hook-friendly factory that returns a stable optimizer instance
|
|
* tied to a callback ref so the callback can change without recreating
|
|
* the optimizer (avoids stale closure issues).
|
|
*/
|
|
export function createStreamingOptimizer(
|
|
onFlush: (accumulated: string) => void,
|
|
maxDelay = 50
|
|
): StreamingOptimizer {
|
|
return new StreamingOptimizer(onFlush, maxDelay);
|
|
}
|