跳到主要内容

轮询 / 长轮询 / 实时通信选型

实时通信的方案很容易一上来就被问成“到底用 WebSocket 还是 SSE”。

但真实项目里,通常至少有四条路线:

  • 轮询
  • 长轮询
  • SSE
  • WebSocket

更稳的做法,不是先选技术名词,而是先判断:

  • 需要单向还是双向通信
  • 更新频率有多高
  • 服务端和网关能承受什么连接模型
  • 前端是否要处理重连、心跳、状态恢复

先看一句话版

方案通信方向连接模型适合场景
轮询客户端主动拉短连接更新频率低、实现要简单
长轮询客户端主动拉单次请求挂起更久更新频率中等、环境受限
SSE服务端单向推长连接流式输出、通知、日志流
WebSocket双向通信长连接聊天、协同编辑、实时互动

1. 轮询

轮询很好理解:客户端按固定间隔发请求,问一次有没有新数据。

async function poll() {
const res = await fetch('/api/tasks/status')
const data = await res.json()
console.log(data)
}

setInterval(poll, 5000)

轮询的优点

  • 实现最简单
  • 对老系统和旧网关友好
  • 出问题时排查路径短
  • 服务端不需要维护大量长连接

轮询的代价

  • 更新不够实时
  • 请求频率高时浪费资源
  • 空数据响应也会持续产生流量
  • 多客户端同时轮询时,服务端压力会抬起来

轮询适合什么场景

  • 任务状态查询
  • 后台报表刷新
  • 低频运营面板
  • 实时要求不高的状态更新

2. 长轮询

长轮询和普通轮询的差别,不在“有没有继续请求”,而在“单次请求会等更久”。

服务端如果暂时没有新数据,不会立刻返回,而是会挂住一段时间;一旦有数据或超时,再返回响应,客户端收到后再发下一次。

async function longPoll() {
const res = await fetch('/api/notifications/subscribe')
const data = await res.json()
console.log(data)
longPoll()
}

longPoll()

长轮询的优点

  • 比普通轮询更接近实时
  • 空转请求更少
  • 仍然基于普通 HTTP,很多基础设施更容易接住

长轮询的代价

  • 服务端要维护挂起请求
  • 并发一高,资源占用就会上来
  • 归根到底还是客户端不断重建请求
  • 双向通信能力还是弱

长轮询适合什么场景

  • 系统环境不方便上 WebSocket
  • 需要比轮询更及时
  • 但实时规模还没有大到要维护专门长连接体系

3. SSE

SSE,Server-Sent Events,是服务端单向持续推送。

const es = new EventSource('/api/stream')

es.onmessage = (event) => {
console.log(event.data)
}

SSE 的优点

  • 服务端持续推,客户端接收简单
  • 天然适合流式输出
  • 浏览器原生支持 EventSource
  • 自动重连模型比 WebSocket 更直接
  • 基于 HTTP,很多代理和网关更容易兼容

SSE 的代价

  • 单向通信
  • 原生 EventSource 不支持自定义请求头
  • 复杂交互和房间模型不如 WebSocket 顺

SSE 适合什么场景

  • AI 输出流
  • 实时日志
  • 系统通知流
  • 进度流
  • 单向状态推送

4. WebSocket

WebSocket 是四种方案里能力最强的一条,但维护成本也最高。

const ws = new WebSocket('wss://example.com/ws')

ws.onmessage = (event) => {
console.log(event.data)
}

WebSocket 的优点

  • 双向通信
  • 单条连接可持续复用
  • 高频实时交互成本更低
  • 更适合房间、频道、实时协作模型

WebSocket 的代价

  • 要自己处理重连、心跳、鉴权、协议、扩缩容
  • 网关和负载均衡配置更敏感
  • 服务端连接管理明显更复杂

WebSocket 适合什么场景

  • 聊天
  • 协同编辑
  • 白板
  • 实时游戏
  • 高频操作回传

怎么选更稳

场景 1:只是偶尔刷新状态

优先看:轮询

场景 2:更新要比轮询更及时,但基础设施受限

优先看:长轮询

场景 3:只需要服务端持续往前端推

优先看:SSE

场景 4:双方都要频繁收发消息

优先看:WebSocket

从系统复杂度看四种方案

方案前端复杂度服务端复杂度实时性双向能力
轮询
长轮询低到中
SSE中到高
WebSocket

一个更实际的判断顺序

技术选型更稳的顺序通常是:

  1. 先问是否真的需要实时
  2. 再问是否需要双向通信
  3. 再问实时频率有多高
  4. 再问网关、部署、后端有没有能力接住长连接

这样判断,一般不会一上来就把方案选重。

常见误区

1. 只要是实时,就直接上 WebSocket

很多单向推送场景,SSE 已经足够,而且链路更轻。

2. 把轮询看成完全落后方案

轮询的价值一直都在:

  • 简单
  • 稳定
  • 便于排查

只要场景实时要求不高,它仍然是合理选择。

3. 长轮询和 WebSocket 混成一回事

长轮询仍然属于 HTTP 请求模型,只是把单次请求挂久一点;WebSocket 是持续双向连接。

4. 只看前端实现,不看服务端和网关约束

很多方案最后不是写法问题,而是:

  • 代理超时
  • 连接数限制
  • 广播能力
  • 多实例同步

和这组其他文章怎么配合看

  • 想看单向流式输出:继续看 SSE
  • 想看双向持续通信:继续看 WebSocket
  • 想把登录态、401、重试一起理顺:看 认证与刷新 Token