Node Websocket 向客户端发送大型数组数据的最优实现方案
WebSocket 大体积对象数组传输优化方案
直接通过JSON.stringify序列化大数组延迟高主要有两个核心原因:一是20万行级别的数据JSON序列化本身CPU开销极高,二是字符串格式的传输冗余度大,相同有效内容的体积远高于二进制格式。以下是可落地的优化方案:
优先方案:二进制序列化 + ArrayBuffer 传输
使用专门的二进制序列化协议替代JSON,同时直接传输二进制数据,序列化速度比JSON快2~5倍,传输体积可降低30%以上,是投入产出比最高的优化方式。这里以轻量高性能的msgpackr库为例:
服务端实现(Node.js)
- 安装依赖:
npm install msgpackr
- 发送逻辑:
const { pack } = require('msgpackr'); // bigDataArray 为你需要发送的20万行对象数组 const binaryData = pack(bigDataArray); // Node.js Buffer 属于 Uint8Array 类型,可直接通过WebSocket发送 ws.send(binaryData);
客户端实现
- 安装同依赖(浏览器环境可直接引入UMD版本)
- 接收逻辑:
import { unpack } from 'msgpackr'; // 指定接收的二进制数据格式为ArrayBuffer ws.binaryType = 'arraybuffer'; ws.onmessage = (event) => { if (event.data instanceof ArrayBuffer) { // 解码二进制数据得到原始对象数组 const originData = unpack(new Uint8Array(event.data)); // 后续业务逻辑处理 } }
注意:不要直接将JSON字符串转为ArrayBuffer传输,这类操作不会降低序列化开销,也不会明显缩小传输体积,无法获得性能收益。
进阶方案:分片传输
如果单包数据体积超过10MB,建议拆分为多个分片发送,避免网络波动导致整包重传:
const binaryData = pack(bigDataArray); const chunkSize = 1024 * 1024; // 单分片大小设为1MB,可根据实际场景调整 const totalChunks = Math.ceil(binaryData.length / chunkSize); for (let i = 0; i < totalChunks; i++) { const start = i * chunkSize; const end = Math.min(start + chunkSize, binaryData.length); const chunk = binaryData.slice(start, end); // 前两个字节存储总分片数和当前分片序号,方便客户端拼接 ws.send(Buffer.concat([Buffer.from([totalChunks, i]), chunk])); }
客户端接收时按序号拼接所有分片后再解码即可。
附加优化:数据压缩
如果你的对象数组重复度很高(比如大量对象的key相同、字段值重复),可以在序列化后增加压缩步骤,重复度高的场景下体积可再降低50%以上:
const zlib = require('zlib'); const binaryData = pack(bigDataArray); zlib.gzip(binaryData, (err, compressedData) => { if (!err) ws.send(compressedData); });
客户端接收后先做gzip解压,再执行二进制解码即可。
额外建议
如果业务场景允许增量更新,优先调整为增量推送逻辑,仅推送发生变化的部分数据,性能收益远高于全量数据传输优化。
内容的提问来源于stack exchange,提问作者Mr.Online
相关产品推荐
相关产品推荐

