From 7c2bb53cf793db712a77ac5eb37bb238c7228dc1 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sun, 26 Apr 2026 13:57:48 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B6=88=E6=81=AF=E5=B9=B3?= =?UTF-8?q?=E6=BB=91=E7=AE=97=E6=B3=95=EF=BC=8C=E4=BF=AE=E5=A4=8D=E6=9E=81?= =?UTF-8?q?=E7=AB=AF=E6=83=85=E5=86=B5=E4=B8=8B=E6=B6=88=E6=81=AF=E5=BB=B6?= =?UTF-8?q?=E8=BF=9F=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=9B=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E6=A8=A1=E6=9D=BFSDK=E5=8D=87=E7=BA=A7=E5=88=B0v1.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/blcsdk.js | 40 +++++++++++++------ .../src/components/ChatRenderer/index.vue | 36 ++++++++++++----- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/frontend/src/blcsdk.js b/frontend/src/blcsdk.js index c318168..59d0db0 100644 --- a/frontend/src/blcsdk.js +++ b/frontend/src/blcsdk.js @@ -9,7 +9,7 @@ }(typeof self !== 'undefined' ? self : this, function() { const exports = {} - const VERSION = '1.0.2' + const VERSION = '1.0.3' /** * 取SDK版本 * @returns {string} "1.0.0" @@ -232,6 +232,9 @@ } } + // 用来统计进队列时间间隔 + const ENQUEUE_INTERVALS_MAX_TIME_RANGE = 3000 + const ENQUEUE_INTERVALS_MAX_LENGTH = 10 // 发送消息时间间隔范围 const MSG_MIN_INTERVAL = 80 const MSG_MAX_INTERVAL = 1000 @@ -265,18 +268,31 @@ } else { let curTime = new Date() let interval = curTime - this._lastEnqueueTime - // 真实的进队列时间间隔模式大概是这样:2500, 300, 300, 300, 2500, 300, ... - // B站消息有缓冲,会一次发多条消息。这里把波峰视为发送了一次真实的WS消息,所以要过滤掉间隔太小的 - if (interval > 1000 || this._enqueueIntervals.length < 5) { - this._enqueueIntervals.push(interval) - if (this._enqueueIntervals.length > 5) { - this._enqueueIntervals.splice(0, this._enqueueIntervals.length - 5) + this._enqueueIntervals.push(interval) + + // 统计最近ENQUEUE_INTERVALS_MAX_TIME_RANGE内的间隔,最多ENQUEUE_INTERVALS_MAX_LENGTH个 + let keepFrom = this._enqueueIntervals.length - 1 + let minKeepFrom = Math.max(this._enqueueIntervals.length - ENQUEUE_INTERVALS_MAX_LENGTH, 0) + let prevIdxPassedTime = 0 + for (; keepFrom > minKeepFrom; keepFrom--) { + let itInterval = this._enqueueIntervals[keepFrom] + prevIdxPassedTime += itInterval + if (prevIdxPassedTime > ENQUEUE_INTERVALS_MAX_TIME_RANGE) { + break } - // 这边估计得尽量大,只要不太早把消息缓冲发完就是平滑的。有MESSAGE_MAX_INTERVAL保底,不会让消息延迟太大 - // 其实可以用单调队列求最大值,偷懒不写了 - this._estimatedEnqueueInterval = Math.max(...this._enqueueIntervals) } - // 上次入队时间还是要设置,否则会太早把消息缓冲发完,然后较长时间没有新消息 + if (keepFrom > 0) { + this._enqueueIntervals.splice(0, keepFrom) + } + + // 这边估计得尽量大,只要不太早把消息缓冲发完就是平滑的。有MSG_MAX_INTERVAL保底,不会让消息延迟太大 + let maxEnqueueInterval = this._enqueueIntervals[0] + for (let interval_ of this._enqueueIntervals) { + if (interval_ > maxEnqueueInterval) { + maxEnqueueInterval = interval_ + } + } + this._estimatedEnqueueInterval = maxEnqueueInterval this._lastEnqueueTime = curTime } @@ -325,7 +341,7 @@ // 消息没发完,计算下次发消息时间 let sleepTime if (numToEmit === 1) { - // 队列中消息数很少,随便定个[MESSAGE_MIN_INTERVAL, MESSAGE_MAX_INTERVAL]的时间 + // 队列中消息数很少,随便定个[MSG_MIN_INTERVAL, MSG_MAX_INTERVAL]的时间 sleepTime = estimatedNextEnqueueRemainTime / this._queue.length sleepTime *= 0.5 + Math.random() if (sleepTime > MSG_MAX_INTERVAL) { diff --git a/frontend/src/components/ChatRenderer/index.vue b/frontend/src/components/ChatRenderer/index.vue index 09a6a73..b5ac9db 100644 --- a/frontend/src/components/ChatRenderer/index.vue +++ b/frontend/src/components/ChatRenderer/index.vue @@ -62,6 +62,9 @@ import MembershipItem from './MembershipItem' import PaidMessage from './PaidMessage' import * as constants from './constants' +// 用来统计进队列时间间隔 +const ENQUEUE_INTERVALS_MAX_TIME_RANGE = 3000 +const ENQUEUE_INTERVALS_MAX_LENGTH = 10 // 要添加的消息类型 const ADD_MESSAGE_TYPES = [ constants.MESSAGE_TYPE_TEXT, @@ -278,18 +281,31 @@ export default { } else { let curTime = new Date() let interval = curTime - this.lastEnqueueTime - // 真实的进队列时间间隔模式大概是这样:2500, 300, 300, 300, 2500, 300, ... - // B站消息有缓冲,会一次发多条消息。这里把波峰视为发送了一次真实的WS消息,所以要过滤掉间隔太小的 - if (interval > 1000 || this.enqueueIntervals.length < 5) { - this.enqueueIntervals.push(interval) - if (this.enqueueIntervals.length > 5) { - this.enqueueIntervals.splice(0, this.enqueueIntervals.length - 5) + this.enqueueIntervals.push(interval) + + // 统计最近ENQUEUE_INTERVALS_MAX_TIME_RANGE内的间隔,最多ENQUEUE_INTERVALS_MAX_LENGTH个 + let keepFrom = this.enqueueIntervals.length - 1 + let minKeepFrom = Math.max(this.enqueueIntervals.length - ENQUEUE_INTERVALS_MAX_LENGTH, 0) + let prevIdxPassedTime = 0 + for (; keepFrom > minKeepFrom; keepFrom--) { + let itInterval = this.enqueueIntervals[keepFrom] + prevIdxPassedTime += itInterval + if (prevIdxPassedTime > ENQUEUE_INTERVALS_MAX_TIME_RANGE) { + break } - // 这边估计得尽量大,只要不太早把消息缓冲发完就是平滑的。有MESSAGE_MAX_INTERVAL保底,不会让消息延迟太大 - // 其实可以用单调队列求最大值,偷懒不写了 - this.estimatedEnqueueInterval = Math.max(...this.enqueueIntervals) } - // 上次入队时间还是要设置,否则会太早把消息缓冲发完,然后较长时间没有新消息 + if (keepFrom > 0) { + this.enqueueIntervals.splice(0, keepFrom) + } + + // 这边估计得尽量大,只要不太早把消息缓冲发完就是平滑的。有MESSAGE_MAX_INTERVAL保底,不会让消息延迟太大 + let maxEnqueueInterval = this.enqueueIntervals[0] + for (let interval_ of this.enqueueIntervals) { + if (interval_ > maxEnqueueInterval) { + maxEnqueueInterval = interval_ + } + } + this.estimatedEnqueueInterval = maxEnqueueInterval this.lastEnqueueTime = curTime }