如何实现JavaScript Buffer存储WebSocket数据并按isMasterFrame规则重置
交易数据缓冲区实现可选方案
首先明确数据适配前提:
isMasterFrame = true时,payload.data为包含bids、asks两个字段的对象,存储对应交易对的全量买卖盘深度数据isMasterFrame = false时,payload.data为增量更新数组,每个元素包含side(ASKS/BIDS)、price、volume字段,volume为0代表删除对应价位的挂单
方案1:Map分层缓冲区(高频场景首选,读写性能最优)
核心逻辑:以交易对符号为一级key,每个交易对下分别存储bids、asks两个Map结构,用价格作为Map的key,实现O(1)复杂度的增删改查。
// 全局缓冲区初始化 const orderbookBuffer = new Map(); // WebSocket消息处理逻辑 function handleMessage(message) { const symbol = message[0]; // 提前清除空字符后解析payload const payload = JSON.parse(message[1].replace(/\0/g, '')); // 处理主帧:重置当前交易对缓冲区 if (payload.isMasterFrame) { const bids = new Map(); const asks = new Map(); // 填充全量买盘数据 Object.values(payload.data.bids || {}).forEach(item => { if (item.volume > 0) bids.set(item.price, item); }); // 填充全量卖盘数据 Object.values(payload.data.asks || {}).forEach(item => { if (item.volume > 0) asks.set(item.price, item); }); orderbookBuffer.set(symbol, { bids, asks, lastUpdate: Date.now() }); return; } // 处理增量帧:仅更新,无主帧时直接跳过无效增量 const currentBook = orderbookBuffer.get(symbol); if (!currentBook) return; payload.data.forEach(item => { const targetMap = item.side === 'ASKS' ? currentBook.asks : currentBook.bids; if (item.volume <= 0) { // 成交量为0,删除对应价位 targetMap.delete(item.price); } else { // 新增/更新对应价位 targetMap.set(item.price, item); } }); currentBook.lastUpdate = Date.now(); }
- 优点:读写性能极高,内存占用低,适配高频交易数据处理场景
- 缺点:需要获取排序后的买卖盘时,需要额外转数组做排序处理
方案2:预排序数组缓冲区(行情展示场景首选)
核心逻辑:每个交易对的买卖盘直接存储为排序完成的数组,买盘按价格降序排列、卖盘按价格升序排列,增量更新时直接操作对应索引位置,无需每次查询都重新排序。
- 优点:可直接获取符合展示要求的排序后深度数据,适合前端行情展示、策略实时调用场景
- 缺点:插入、删除操作时间复杂度为O(n),交易对深度较大时性能低于Map方案
方案3:带历史快照的环形缓冲区(回溯场景首选)
核心逻辑:固定存储最近N个主帧对应的完整深度快照,维护一个最大长度为N的数组作为环形队列,每次收到主帧时将当前全量缓冲区深拷贝后入队,超过容量则出队最早的快照,增量更新仅修改最新的快照数据。
- 优点:可回溯历史行情状态,适合行情回测、异常排查、策略复盘场景
- 缺点:内存占用高,需要频繁做深拷贝,性能低于纯实时缓冲区方案
内容的提问来源于stack exchange,提问作者user1285928
相关产品推荐
相关产品推荐

