@@ -140,8 +140,8 @@ async function applyGroupHash() {
140140 let displayMessages = [ ]
141141 /** @type {object[] } 当前频道原始消息行(与 API messages 一致),供增量 merge */
142142 let rawMessages = [ ]
143- /** @type {object[] } 待合并的 WS 消息行(microtask 防抖批处理 ) */
144- const pendingNewEvents = [ ]
143+ /** @type {Map<string, object> } eventId → 最新待合并消息行(后写覆盖前写 ) */
144+ const pendingEventMap = new Map ( )
145145 /** @type {boolean } 是否已排队一次 microtask 批处理 */
146146 let patchScheduled = false
147147
@@ -173,85 +173,46 @@ async function applyGroupHash() {
173173 }
174174
175175 /**
176- * 将新到的 DAG 事件增量合并进 displayMessages 并追加到虚拟列表,
177- * 避免全量重绘导致的闪烁与滚动跳动。
178- * @param {object[] } newEvents 尚未合并进 rawMessages 的新事件行
179- * @returns {Promise<void> }
180- */
181- async function patchNewMessages ( newEvents ) {
182- if ( ! newEvents . length ) return
183- if ( lastChannelMeta ?. type === 'list' || ! msgVirtualList ) {
184- await loadMessages ( )
185- return
186- }
187- if ( newEvents . some ( e => e ?. type === 'pin_message' || e ?. type === 'unpin_message' ) ) {
188- await loadMessages ( )
189- return
190- }
191- const known = new Set (
192- rawMessages . map ( m => m ?. eventId || m ?. id ) . filter ( Boolean ) ,
193- )
194- const toAdd = [ ]
195- for ( const e of newEvents ) {
196- const id = e ?. eventId || e ?. id
197- if ( id && known . has ( id ) ) continue
198- if ( id ) known . add ( id )
199- toAdd . push ( e )
200- }
201- if ( ! toAdd . length ) return
202-
203- const prevLen = displayMessages . length
204- const merged = mergeChannelMessagesForDisplay ( [ ...rawMessages , ...toAdd ] )
205- for ( let i = 0 ; i < prevLen ; i ++ ) {
206- const a = displayMessages [ i ] ?. eventId ?? displayMessages [ i ] ?. id
207- const b = merged [ i ] ?. eventId ?? merged [ i ] ?. id
208- if ( a !== b ) {
209- await loadMessages ( )
210- return
211- }
212- }
213- const appended = merged . slice ( prevLen )
214- if ( ! appended . length ) {
215- await loadMessages ( )
216- return
217- }
218- displayMessages . push ( ...appended )
219- rawMessages . push ( ...toAdd )
220- if ( typeof msgVirtualList . appendItem === 'function' ) {
221- for ( const item of appended )
222- await msgVirtualList . appendItem ( item , false )
223- if ( msgScrollContainer )
224- msgScrollContainer . scrollTop = msgScrollContainer . scrollHeight
225- }
226- else await loadMessages ( )
227-
228- void attachLastMessageTimeline ( displayMessages ) . catch ( e => {
229- Sentry . captureException ( e )
230- console . error ( 'attachLastMessageTimeline failed:' , e )
231- } )
232- }
233-
234- /**
235- * 调度一次增量消息更新(防抖:同一 microtask 前多次入队合并为一批)。
236- * @param {object } row 新到的频道消息行(与 API message 行形状一致)
176+ * 将 DAG 消息行调度进增量 patch 队列(同一 eventId 后写覆盖)。
177+ * @param {object } line 消息行(含 eventId 字段)
237178 * @returns {void }
238179 */
239- function scheduleMessagePatch ( row ) {
240- if ( ! row || typeof row !== 'object' ) return
241- pendingNewEvents . push ( row )
180+ function scheduleMessagePatch ( line ) {
181+ if ( ! line || typeof line !== 'object' ) return
182+ const key = line . eventId || line . content ?. chatLogEntryId || JSON . stringify ( line )
183+ pendingEventMap . set ( key , line )
242184 if ( patchScheduled ) return
243185 patchScheduled = true
244- queueMicrotask ( async ( ) => {
245- const eventsToProcess = pendingNewEvents . splice ( 0 )
186+ queueMicrotask ( ( ) => {
246187 patchScheduled = false
247- if ( signal . aborted ) return
188+ if ( signal . aborted ) {
189+ pendingEventMap . clear ( )
190+ return
191+ }
248192 try {
249- await patchNewMessages ( eventsToProcess )
193+ const lines = [ ...pendingEventMap . values ( ) ]
194+ pendingEventMap . clear ( )
195+ if ( ! lines . length ) return
196+ let changed = false
197+ for ( const l of lines ) {
198+ const idx = rawMessages . findIndex ( r => r . eventId === l . eventId )
199+ if ( idx >= 0 ) {
200+ rawMessages [ idx ] = l
201+ changed = true
202+ }
203+ else {
204+ rawMessages . push ( l )
205+ changed = true
206+ }
207+ }
208+ if ( ! changed ) return
209+ displayMessages = mergeChannelMessagesForDisplay ( rawMessages )
210+ msgVirtualList ?. refresh ?. ( )
250211 }
251212 catch ( e ) {
252213 Sentry . captureException ( e )
253- console . error ( 'patchNewMessages failed, falling back to loadMessages:' , e )
254- await loadMessages ( )
214+ console . error ( 'scheduleMessagePatch flush failed, falling back to loadMessages:' , e )
215+ void loadMessages ( )
255216 }
256217 } )
257218 }
0 commit comments