前端实时通信方案对比:WebSocket vs SSE vs setInterval 轮询

📢 前言

在前端开发中,实时数据获取是常见需求。本文从前端视角对比三种主流方案:WebSocketSSE (Server-Sent Events)setInterval 轮询,帮你做出最佳技术选型。


📊 核心对比表格

特性 WebSocket SSE setInterval 轮询
通信方向 全双工(双向通信) 单工(服务端→客户端) 半双工(客户端主动拉取)
实时性 毫秒级 亚秒级 依赖轮询间隔(最低秒级)
协议类型 独立协议(ws:///wss:// 基于 HTTP 长连接 基于 HTTP 短连接
前端复杂度 高(需管理连接状态) 中(事件监听) 低(定时器 + fetch)
移动端电量消耗 高(频繁唤醒射频模块)
兼容性 IE10+ Edge12+(需 Polyfill) 全兼容

🔍 技术方案详解

1. WebSocket

📌 核心特性

  • 双向实时通信:客户端与服务端可同时发送消息
  • 低延迟:适用于高频交互场景(如在线游戏、聊天室)
  • 二进制支持:可传输 ArrayBuffer、Blob 等二进制数据

💻 前端实现

javascript 复制代码
const ws = new WebSocket('wss://api.example.com');

// 连接成功
ws.onopen = () => {
  console.log('WebSocket connected');
  ws.send('Hello Server!');
};

// 接收消息
ws.onmessage = (event) => {
  console.log('Received:', event.data);
};

// 错误处理
ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

// 关闭连接
ws.onclose = () => {
  console.log('WebSocket closed');
};

⚠️ 注意事项

  • 需手动实现心跳检测防止断开
  • iOS 后台运行超过 30 秒可能断开连接
  • 浏览器同一域名最多保持 6 个 WebSocket 连接

2. SSE (Server-Sent Events)

📌 核心特性

  • 服务端推送:服务端可主动向客户端推送数据
  • 自动重连:内置断线重连机制(默认 3 秒)
  • 轻量级:基于 HTTP 协议,兼容现有基础设施

💻 前端实现

javascript 复制代码
const sse = new EventSource('/api/sse');

// 监听自定义事件
sse.addEventListener('stock_update', (e) => {
  console.log('Stock price:', JSON.parse(e.data));
});

// 通用消息监听
sse.onmessage = (e) => {
  console.log('Message:', e.data);
};

// 错误处理(会自动重连)
sse.onerror = () => {
  console.error('SSE connection error');
};

⚠️ 注意事项

  • 不支持 IE 浏览器(需使用 eventsource polyfill)
  • 只能传输文本数据(二进制需 Base64 编码)
  • Chrome 同一域名最多 6 个 SSE 连接

3. setInterval 轮询

📌 核心特性

  • 简单易用:无需服务端特殊支持
  • 兼容性极佳:所有浏览器均支持
  • 成本可控:适合低频更新场景

💻 前端实现

javascript 复制代码
let pollTimer;

// 启动轮询
function startPolling() {
  pollTimer = setInterval(async () => {
    try {
      const res = await fetch('/api/data');
      const data = await res.json();
      updateUI(data);
    } catch (err) {
      console.error('Polling error:', err);
    }
  }, 5000); // 5秒间隔
}

// 停止轮询
function stopPolling() {
  clearInterval(pollTimer);
}

// 页面隐藏时暂停轮询
document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    stopPolling();
  } else {
    startPolling();
  }
});

⚠️ 注意事项

  • 高频轮询会导致性能问题(推荐间隔 ≥30 秒)
  • 移动端电量消耗显著增加
  • 可能产生陈旧数据(需配合 ETag 等机制)

🚀 选型建议

决策流程图

javascript 复制代码
是否需要双向通信?
├── 是 → 选择 WebSocket
└── 否 → 是否需要服务端主动推送?
       ├── 是 → 选择 SSE
       └── 否 → 数据更新频率?
               ├── ≤30秒 → 优先考虑 SSE
               └── >30秒 → setInterval 轮询

场景化推荐

场景 推荐方案 理由
在线聊天/多人游戏 WebSocket 需要双向高频通信
股票行情/实时日志 SSE 服务端主动推送,节省带宽
天气预报/配置更新 setInterval 轮询 低频请求,实现简单

🛠 优化技巧

WebSocket

🔧 ​​心跳包与 Nginx 超时的关系​

​核心原则​

  • ​心跳间隔 < Nginx 超时时间​

    例如:若 Nginx 配置 proxy_read_timeout 60s,则建议心跳间隔设为 ​​50-55秒​​,需满足:

    复制代码
    心跳间隔 + 网络抖动缓冲 < Nginx超时时间
  • 使用二进制协议(如 Protocol Buffers)压缩数据

  • 添加心跳包检测连接状态

javascript 复制代码
// WebSocket 心跳机制
const HEARTBEAT_INTERVAL = 50 * 1000; // 50秒
let heartbeatTimer;

ws.onopen = () => {
  // 开启心跳
  heartbeatTimer = setInterval(() => {
    if (ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ type: 'heartbeat' }));
    }
  }, HEARTBEAT_INTERVAL);

  // 重置心跳计数器
  ws.onmessage = () => {
    clearTimeout(heartbeatTimer);
    heartbeatTimer = setInterval(...); // 重新计时
  };
};

SSE

  • 利用 lastEventId 实现断点续传
javascript 复制代码
// 从 localStorage 读取最后事件ID
let lastEventId = localStorage.getItem('lastSSEId') || '0';

const sse = new EventSource(`/api/sse?lastId=${lastEventId}`);

sse.addEventListener('message', (e) => {
  // 更新最后事件ID
  lastEventId = e.lastEventId;
  localStorage.setItem('lastSSEId', lastEventId);
  
  // 处理数据
  console.log('收到数据:', e.data);
});

sse.addEventListener('error', () => {
  sse.close();
  setTimeout(() => {
    // 断线重连时自动携带 lastEventId
    new EventSource(`/api/sse?lastId=${lastEventId}`);
  }, 3000);
});

setInterval 轮询

  • 使用智能退避策略
javascript 复制代码
let retryCount = 0;
function smartPoll() {
  fetch('/api/data')
    .then(resetRetry)
    .catch(() => {
      const delay = Math.min(2000 * 2 ** retryCount, 30000);
      setTimeout(smartPoll, delay);
      retryCount++;
    });
}

💡 总结

方案 核心优势 最佳场景
WebSocket 双向实时通信 在线协作、实时游戏
SSE 服务端推送 + 自动重连 监控仪表盘、实时通知
setInterval 轮询 简单易用 + 全兼容 低频数据更新、兼容性要求高场景

最终建议:根据业务需求选择合适方案,对于复杂场景可组合使用(如 WebSocket + SSE)实现最佳效果!

相关推荐
水冗水孚几秒前
使用nodejs的express框架实现大文件上传的功能,附完整前后端github代码
javascript·node.js·express
GIS之路1 分钟前
OpenLayers 创建坐标系统
前端
前端日常开发1 分钟前
你真的懂vue组件的封装?
前端
error_cn1 分钟前
python代码优化策略
前端
error_cn4 分钟前
unset命令常见错误
前端
Aniugel5 分钟前
Lighthouse 前端性能优化:从一个DEMO项目入手,一步一步提升性能评分
性能优化
星河丶6 分钟前
React 中的合成事件
前端·react.js
ZFJ_张福杰1 小时前
【Flutter】性能优化总结
flutter·性能优化
大熊猫侯佩1 小时前
Swift 初学者交心:在 Array 和 Set 之间我们该如何抉择?
数据结构·性能优化·swift
小小小小宇2 小时前
ESLint 插件笔记
前端