websocket.onmessage 中直接更新 dom 会卡顿,因高频消息触发强制同步重排;应缓存数据至 map,再用 requestanimationframe 批量更新 dom。

为什么 WebSocket.onmessage 里直接更新 DOM 会卡顿
行情数据每秒可能推送几十条,onmessage 触发频率远超浏览器重绘帧率(通常 60fps ≈ 16ms/帧)。如果每次收到消息都立即操作 document.getElementById('price-600519').innerText = data.price,会造成大量 layout thrashing 和强制同步重排。
真正可行的做法是把更新暂存、批量合并、错峰执行:
- 用
Map缓存各股票最新值,只做内存赋值,不碰 DOM - 用
requestAnimationFrame或setTimeout(fn, 0)延迟到下一帧再批量刷新对应元素 - 对价格变化极小的标的(如涨跌幅
订阅消息发出去了但没收到数据?检查这三处
常见现象是 onopen 触发成功,也调用了 ws.send() 发送 {"type":"subscribe","symbols":["SH600519"]},但后续无 onmessage。问题往往不在连接本身,而在协议细节:
- 服务端是否要求首次消息必须是认证包?比如先发
{"type":"auth","token":"abc123"},再发订阅,否则静默丢弃 - symbol 格式是否匹配?
"SH600519"和"600519.SH"是不同标的,大小写、后缀、前缀必须和服务端文档严格一致 - 是否漏了心跳响应?有些行情服务在建立连接后 30 秒内未收到客户端
ping或服务端pong,会主动断连,表现为“连接后几秒就onclose”
JSON vs 二进制:怎么选才不拖慢解析
实测显示,相同行情字段下,文本 JSON 的解析耗时是 Protocol Buffer 的 3–5 倍,体积大 60%+。但二进制不是万能解药——它带来额外复杂度:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 前端需引入
protobuf.js或手写解码逻辑,增加包体积和维护成本 - 调试困难:
console.log(e.data)看不到明文,必须用配套工具或自定义解析器才能读 - 若服务端推送频率不高(如每秒 ≤ 5 条),JSON 的性能劣势几乎不可感知,此时优先选可读性
折中方案:用精简键名 JSON(如 {"s":"SH600519","p":1725.3,"v":12800,"t":1748185200123}),既减少传输量,又保留调试能力。
重连后数据断层?快照补发不是可选项
网络抖动导致断连再重连,仅靠重连后继续收增量,大概率错过断连期间的行情变动。真实场景中,必须依赖服务端的快照能力:
- 重连成功后,前端应立即发送
{"type":"snapshot","symbols":["SH600519"]}请求全量状态 - 服务端返回的快照格式需与增量一致(如同样含
t时间戳),方便前端统一处理 - 前端收到新消息时,对比本地缓存的
lastTimestamp,若msg.t 则直接丢弃,防止旧数据倒灌
这个时间戳比对逻辑极易被忽略,但它是保证行情连续性的最后一道防线。










