perf(ui): cache visWithIdx to skip O(N) scan on render window expansion

This commit is contained in:
AlexeyDsov
2026-05-25 18:34:00 +03:00
parent f0dfe116ca
commit 08277fcd9c
+23 -4
View File
@@ -265,10 +265,15 @@ function _statusCardHtml(card){
const MESSAGE_RENDER_WINDOW_DEFAULT=50;
let _messageRenderWindowSid=null;
let _messageRenderWindowSize=MESSAGE_RENDER_WINDOW_DEFAULT;
// Cached visWithIdx array — invalidated when S.messages.length changes.
let _visWithIdxCache=null;
let _visWithIdxCacheLen=0;
function _resetMessageRenderWindow(sid){
_messageRenderWindowSid=sid||null;
_messageRenderWindowSize=MESSAGE_RENDER_WINDOW_DEFAULT;
_clearRenderCache();
_visWithIdxCache=null;
_visWithIdxCacheLen=0;
}
// ── renderMd / _renderUserFencedBlocks cache ──────────────────────────────
@@ -6120,15 +6125,29 @@ function renderMessages(options){
? (()=>{const row=document.createElement('div');row.innerHTML=`<div class="compression-turn"><div class="compression-turn-blocks">${_compressionReferenceCardHtml(referenceText,false)}${_preservedCompressionTaskListCardsHtml(preservedCompressionTaskMessages)}</div></div>`;return row.firstElementChild;})()
: null;
let preservedCompressionTaskCardsAttached=!!referenceNode;
const visWithIdx=[];
// Cache visWithIdx so expanding the render window (Load earlier) doesn't
// re-scan S.messages from scratch. Invalidate only when the message array
// length changes — i.e. new messages arrived or session was truncated.
if(!_visWithIdxCache || _visWithIdxCacheLen !== S.messages.length){
const rebuilt=[];
let ri=0;
for(const m of S.messages){
if(!m||!m.role||m.role==='tool'){ri++;continue;}
if(_isPreservedCompressionTaskListMessage(m)){ri++;continue;}
const hasTc=Array.isArray(m.tool_calls)&&m.tool_calls.length>0;
const hasTu=Array.isArray(m.content)&&m.content.some(p=>p&&p.type==='tool_use');
if(msgContent(m)||m._statusCard||m.attachments?.length||(m.role==='assistant'&&(hasTc||hasTu||_messageHasReasoningPayload(m)))) rebuilt.push({m,rawIdx:ri});
ri++;
}
_visWithIdxCache=rebuilt;
_visWithIdxCacheLen=S.messages.length;
}
const visWithIdx=_visWithIdxCache;
const preservedCompressionRawIdxs=[];
let rawIdx=0;
for(const m of S.messages){
if(!m||!m.role||m.role==='tool'){rawIdx++;continue;}
if(_isPreservedCompressionTaskListMessage(m)){preservedCompressionRawIdxs.push(rawIdx);rawIdx++;continue;}
const hasTc=Array.isArray(m.tool_calls)&&m.tool_calls.length>0;
const hasTu=Array.isArray(m.content)&&m.content.some(p=>p&&p.type==='tool_use');
if(msgContent(m)||m._statusCard||m.attachments?.length||(m.role==='assistant'&&(hasTc||hasTu||_messageHasReasoningPayload(m)))) visWithIdx.push({m,rawIdx});
rawIdx++;
}
// Show a top affordance when earlier transcript content exists either in