最危险做法是直接用json.stringify()发送大json,会导致主线程卡顿、内存溢出、长任务;应改用web worker序列化、二进制编码、差分推送和流式解析等方案。

直接用 JSON.stringify() 发送大 JSON 是最常见也最危险的做法——它会在主线程卡住、吃光内存、触发长任务,尤其在万人级房间推送排行榜或全量状态时极易崩盘。关键不是“能不能发”,而是“怎么不卡、不崩、不丢”。
拆掉主线程的炸弹:把序列化移出渲染线程
10MB JSON 在主线程里调一次 JSON.stringify() 就可能阻塞 100ms 以上,滚动和动画立刻掉帧。必须剥离:
- 用
Web Worker承担序列化任务,主页面只负责postMessage()传原始对象,Worker 内完成JSON.stringify()或更优方案后回传 ArrayBuffer - 对超大结构(如含循环引用、Date/Map/Set 的数据),先用
structuredClone()深拷贝再交给 Worker,避免主线程意外阻塞 - 禁用同步读取:不要
localStorage.getItem() + JSON.parse()连用,改用 IndexedDB 存储预序列化后的二进制块,按需流式加载
别 stringify,改用享元+二进制编码
高频消息(如弹幕、点击反馈)字段高度重复,反复序列化相同字符串(如 "type": "click")纯属浪费:
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
- 用享元模式缓存固定字段值,例如将
"chat"、"join"、"leave"提前转为共享 Uint8Array 片段,拼接时直接 copy 而非字符串拼接 - 放弃 JSON 文本帧,切到二进制帧(
Opcode=0x2),用Uint16Array编码消息头(类型+长度),再接紧凑 payload,体积比 JSON 小 50% 以上 - 结构复杂但字段稳定时,上 Protocol Buffers 或 MessagePack,JS 库(protobufjs / msgpack-lite)支持直接生成 typed array,零字符串开销
服务端协同:不推全量,只发差分
前端再快,也扛不住服务端每秒往一万个客户端广播 200KB 的 JSON —— 真正瓶颈常在广播路径本身:
- 服务端维护状态快照(Redis Hash 或本地 Caffeine),新用户加入只拉一次全量;后续仅推送 delta(如
{"rank": 3, "score_delta": +120}),体积常压到原 JSON 的 3% 以内 - 启用消息合并(burst merge):100ms 时间窗内同类型事件(如 37 条“点赞”)打包成一个数组下发,客户端统一解析,减少帧数量和序列化调用次数
- 广播前按房间 ID、用户在线状态、权限等级三层过滤,跳过僵尸连接和无权接收者,避免无效序列化
兜底与监控:让问题暴露得早一点
再好的优化也需可观测性:
- 在 Worker 中加耗时监控:
performance.now()记录每次序列化耗时,超过 20ms 自动告警并降级为简化格式 - 前端用 Chrome DevTools 的 Network → WebSocket → Frames 标签,确认是否真在发二进制帧、帧长是否稳定控制在 126 字节内(避开长度字段膨胀)
- 对 >1MB 的 JSON,强制走流式解析:用
JSONStream或clarinet边接收边处理,不等整包收完就启动渲染或入库
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










