如何准确统计WebSocket连接的已发送字节数?
WebSocket 发送字节数统计方案
要准确统计WebSocket实际通过网络发送的字节数,确实不能直接在send()调用后累加数据长度——正如你所说,send()只是把数据加入发送队列,返回时数据还没真正发出去。而死循环轮询bufferedAmount的方式会阻塞主线程,影响性能,显然不可取。
目前WebSocket API没有提供直接的"数据发送完成"事件,不过可以通过bufferedAmount属性结合非阻塞的检查逻辑来实现准确统计,下面是具体方案:
核心思路
维护一个待确认发送的队列,每次调用send()时,记录当前的bufferedAmount和要发送的数据长度;然后通过requestAnimationFrame(或低频率的setTimeout)周期性检查bufferedAmount的变化,当bufferedAmount降到小于等于发送前的数值时,说明该数据块已经完全发送出去,此时再累加字节数。
代码实现
let bytesSent = 0; // 存储待确认的发送任务:{ dataLength: 字节数, preSendBuffered: 发送前的bufferedAmount } const pendingSends = []; function sendAndTrack(webSocket, data) { const dataLength = data.length; const preSendBuffered = webSocket.bufferedAmount; webSocket.send(data); pendingSends.push({ dataLength, preSendBuffered }); // 启动检查逻辑 checkPendingSends(webSocket); } function checkPendingSends(webSocket) { let index = 0; while (index < pendingSends.length) { const task = pendingSends[index]; // 当当前bufferedAmount小于等于发送前的数值,说明该数据已发送完成 if (webSocket.bufferedAmount <= task.preSendBuffered) { bytesSent += task.dataLength; // 从队列中移除已完成的任务 pendingSends.splice(index, 1); } else { index++; } } // 如果还有待确认任务,继续下一轮检查 if (pendingSends.length > 0) { requestAnimationFrame(() => checkPendingSends(webSocket)); } }
方案优势
- 非阻塞:用
requestAnimationFrame替代死循环轮询,只会在浏览器重绘间隙执行检查,不会阻塞主线程,对性能影响极小。 - 准确性:通过对比发送前后的
bufferedAmount,能精准判断单个数据块是否已发送完成。 - 可扩展:队列结构支持批量发送场景,能同时跟踪多个待确认的发送任务。
补充说明
如果你的场景对统计精度要求不是极高(比如允许少量延迟统计),也可以监听bufferedamountlow事件:
webSocket.bufferedAmountLowThreshold = 0; webSocket.addEventListener('bufferedamountlow', () => { // 此时队列中待发送的数据已全部发完,可以累加之前记录的所有待统计字节数 // 注意:这种方式适合批量统计,无法精准对应单个send操作 });
不过这种方式只能知道队列清空的时机,无法精确对应每一次send的数据块,所以队列跟踪的方案更适合需要精准统计的场景。
内容的提问来源于stack exchange,提问作者Roj
相关产品推荐
相关产品推荐

