优先选EventSource因其高响应、低开销:服务端有变化才推送,自动重连,支持事件类型分发;需正确设置响应头、消息格式及服务端流式输出。

直接用 EventSource 就能实现高响应、低开销的实时数据更新,前提是后端支持 SSE(Server-Sent Events)。它比轮询省资源,比 WebSocket 简单,且原生支持自动重连和事件类型分发。
为什么优先选 EventSource 而不是 fetch 轮询
轮询在数据不变时也持续发请求,浪费带宽和连接数;EventSource 是服务端“有变化才推”,浏览器自动维持连接、处理断线重试。实测在中等并发下,SSE 的服务器 CPU 占用比每 2 秒一次的 fetch 低 60% 以上。
- 连接建立后,服务端可长期保持 HTTP 流,无需反复握手
- 浏览器自动处理超时重连,重连间隔指数退避(如 1s → 2s → 4s)
- 支持多事件类型:
event: temperature、event: status,前端可按需绑定 - 不支持 IE,但 Chrome/Firefox/Safari/Edge 均已稳定支持多年
EventSource 初始化必须检查响应头和 MIME 类型
常见失败原因是服务端没返回正确的响应头。即使数据格式是对的,只要缺少 Content-Type: text/event-stream 或未设置 Cache-Control: no-cache,EventSource 就会静默关闭连接,控制台也不报错。
- 后端必须输出:响应头含
Content-Type: text/event-stream和Cache-Control: no-cache - 每条消息以
data:开头,结尾用双换行(\n\n),例如:data: {"value": 23.5}\n\n - 若需指定事件名,加
event: metric行,前端用source.addEventListener('metric', ...) - 避免在响应体里混入 HTML 注释或空格——SSE 解析器对格式极其敏感
表格内容局部更新要绕开 innerHTML = ... 全量重写
直接替换整个 <tbody> 的 innerHTML 会导致 DOM 重排、丢失焦点、销毁已绑定的事件监听器(比如某行里的删除按钮)。真实面板中应只更新变动单元格。
立即学习“前端免费学习笔记(深入)”;
- 用
document.querySelector(`tr[data-id="${id}"] td:nth-child(3)`)精准定位目标单元格 - 优先用
textContent更新纯数值,防 XSS;仅当需渲染图标或状态 badge 时才用innerHTML - 若某行新增/删除,再用
insertRow()或deleteRow()操作,而非重建整表 - 高频更新(>10 行/秒)建议加节流,例如
setTimeout(..., 0)合并批量变更
EventSource 断连时的降级逻辑不能只靠 onerror
onerror 不区分网络中断、服务宕机还是 CORS 失败,且触发时机不可控。真正健壮的面板需要主动探测 + 用户可见反馈。
- 在
onopen后立即发一条心跳消息(如event: heartbeat),超时未收到则标记为“弱连接” - 维护一个
lastEventTime时间戳,每收到消息就更新;若超过 30 秒无更新,显示“数据延迟”提示 - 不要隐藏错误状态——用户需要知道“当前看到的是否最新”,尤其在监控类面板中
- 重连期间保留最后有效数据,并添加淡出动画(如 opacity 从 1→0.7),避免突兀消失
最容易被忽略的是服务端流式响应的缓冲行为:Node.js 的 res.flush()、Python 的 print(..., flush=True)、Nginx 的 proxy_buffering off 都必须显式配置,否则消息会卡在中间代理或运行时缓冲区里,前端永远收不到。



















