2026-04-25 03:34:31 +08:00
|
|
|
// 聊天室消息队列工具,用于后续迁移接收消息、批量渲染和节流刷新逻辑。
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 创建可控长度的消息队列。
|
|
|
|
|
*
|
|
|
|
|
* @param {{limit?:number, onFlush?:(messages:unknown[])=>void, scheduler?:(callback:()=>void)=>unknown}} options
|
|
|
|
|
* @returns {{enqueue:(message:unknown)=>number, flush:()=>unknown[], scheduleFlush:()=>void, clear:()=>void, size:()=>number, toArray:()=>unknown[]}}
|
|
|
|
|
*/
|
|
|
|
|
export function createMessageQueue(options = {}) {
|
|
|
|
|
const limit = Math.max(Number.parseInt(options.limit, 10) || 200, 1);
|
|
|
|
|
const queue = [];
|
2026-04-25 08:18:01 +08:00
|
|
|
// 标记当前帧是否已排队刷新,避免高频消息在同一帧内重复触发渲染。
|
2026-04-25 03:34:31 +08:00
|
|
|
let flushScheduled = false;
|
|
|
|
|
|
|
|
|
|
const scheduler = typeof options.scheduler === "function"
|
|
|
|
|
? options.scheduler
|
|
|
|
|
: (callback) => {
|
2026-04-25 08:18:01 +08:00
|
|
|
// 浏览器优先跟随 RAF 合并刷新,测试或无 RAF 环境回退到短 timeout。
|
2026-04-25 03:34:31 +08:00
|
|
|
const requestFrame = globalThis.requestAnimationFrame || ((handler) => globalThis.setTimeout(handler, 16));
|
|
|
|
|
|
|
|
|
|
return requestFrame(callback);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const flush = () => {
|
|
|
|
|
flushScheduled = false;
|
|
|
|
|
const messages = queue.splice(0, queue.length);
|
|
|
|
|
|
|
|
|
|
if (messages.length && typeof options.onFlush === "function") {
|
|
|
|
|
options.onFlush(messages);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return messages;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
enqueue(message) {
|
|
|
|
|
queue.push(message);
|
|
|
|
|
|
2026-04-25 08:18:01 +08:00
|
|
|
// 队列超过上限时丢弃最旧消息,避免离线积压拖慢后续批量渲染。
|
2026-04-25 03:34:31 +08:00
|
|
|
while (queue.length > limit) {
|
|
|
|
|
queue.shift();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return queue.length;
|
|
|
|
|
},
|
|
|
|
|
flush,
|
|
|
|
|
scheduleFlush() {
|
|
|
|
|
if (flushScheduled) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flushScheduled = true;
|
|
|
|
|
scheduler(flush);
|
|
|
|
|
},
|
|
|
|
|
clear() {
|
|
|
|
|
queue.splice(0, queue.length);
|
|
|
|
|
flushScheduled = false;
|
|
|
|
|
},
|
|
|
|
|
size() {
|
|
|
|
|
return queue.length;
|
|
|
|
|
},
|
|
|
|
|
toArray() {
|
|
|
|
|
return [...queue];
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|