毫秒级行情刷新依赖WebSocket稳定性、服务端精准广播、数据压缩与前端节流协同实现,而非单纯提高渲染频率;须用wss://、指数退避重连、增量推送、内存缓冲+异步UI更新及Nginx正确透传配置。

毫秒级行情刷新不是靠调高前端渲染频率实现的,而是由 WebSocket 连接稳定性、服务端精准广播、数据格式压缩与前端节流策略共同决定的。单纯在 onmessage 里直接更新 DOM,哪怕数据是毫秒到达,UI 也会卡顿甚至丢帧。
WebSocket 连接必须用 wss:// 且带指数退避重连
HTTP 页面下使用 ws:// 会被浏览器直接拦截,生产环境必须用 wss://。连接断开后若立即重试,会在开盘瞬间引发雪崩式重连请求,压垮网关或触发风控。
- 首次重连延迟设为
100ms,后续每次翻倍(200ms→400ms→ …),上限控制在30s - 重连前清空已订阅列表,避免恢复后重复发送
subscribe导致服务端重复推送 - 在
onopen回调里才发送订阅消息,不要在new WebSocket()后立刻发 - 监听
onerror但不依赖它判断断连——有些网络抖动只触发onclose,需两者都处理
服务端推送必须按 symbol 分组 + 增量更新
全量广播(即每只股票变动都推给所有用户)在 50 只股票以上就会产生严重冗余流量;而前端收到全量数据再 diff,CPU 占用飙升,尤其在低端设备上易掉帧。
- 服务端应维护
Map<string set>></string>结构,按股票代码索引连接集合 - 行情引擎收到新 tick 后,只向对应
symbol的客户端集合调用ws.send() - 推送内容应为增量结构,例如:
{"symbol":"600519.SH","bid":[[1895.0,1200],[1894.5,800]],"ask":[[1896.0,950]]},而非包含全部字段的大 JSON - 对逐笔成交等高频数据,建议启用
permessage-deflate压缩,实测可降低 40%+ 传输体积
前端渲染必须跳过主线程阻塞 + 局部更新
直接在 onmessage 中调用 document.getElementById().innerText = ... 是最常见性能陷阱。DOM 操作同步触发样式计算与布局,连续高频调用会导致强制同步布局(Layout Thrashing)。
- 把收到的数据先存入内存数组(如
tickBuffer),用requestIdleCallback或setTimeout(..., 0)批量合并后更新 UI - 盘口表格只替换变化档位的
textContent,不重建整行 DOM;价格列用text-align: right,数量列用text-align: left,避免 JS 计算对齐 - 对成交热力图等可视化组件,改用
requestAnimationFrame控制绘制节奏,确保不高于 60fps - 禁用盘口区域的文本选中:
user-select: none,防止鼠标误拖拽打断盯盘
nginx 代理必须透传 Upgrade 头并关闭缓冲
即使前后端都写对了,Nginx 配置错误也会让 WebSocket 连接在 60 秒后静默断开,表现为“看似连着,但收不到任何数据”。
-
proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection "upgrade"缺一不可 - 必须显式设置
proxy_buffering off,否则 Nginx 会缓存未满包的数据,导致延迟突增 -
proxy_read_timeout建议设为86400(24 小时),避免长连接被意外切断 - 检查响应头是否含
101 Switching Protocols,若返回200或302,说明 Nginx 把 WebSocket 请求当普通 HTTP 转发了
真正难的不是“连上”,而是连接持续数小时不丢帧、不积压、不卡顿。很多团队卡在「能跑通 demo」和「上线扛住开盘流量」之间,差的往往就是心跳保活逻辑没覆盖边缘断网场景、或者前端没做数据缓冲就直冲 DOM 更新。这些细节不写进代码注释,下次交接时大概率被删掉。


















