你有没有过这种体验:在网页聊天室里,对方明明已经发了消息,你却要等好几秒才看到;或者刷新页面,数据才“啪”地一下跳出来。那种卡顿感,就像你在等人回微信,对方明明在线,就是半天不回,你每隔几秒就刷新一下对话框——累心又累电。
其实,这背后有一个技术名字:AJAX长轮询。它曾经是实时通信的“救星”,但随着用户期待越来越高,它的短板暴露无遗。今天,我们就来聊聊为什么AJAX轮询总慢半拍,以及Websocket是如何让性能“原地起飞”的。
一、AJAX轮询:那个“勤快但笨拙”的老邻居
1.1 它是怎么工作的?
想象一下,你开了一家奶茶店,顾客想知道自己的奶茶好了没。在没有Websocket的年代,顾客只能每隔30秒就打电话问一句:“我的奶茶好了吗?”
这就是短轮询:客户端定时向服务器发送请求,服务器立刻回复“还没好”或“好了”。
(脑补图:客户端每隔30秒发一个请求,服务器总是回复“没有”,直到最后才回复“好了”)
但这样太浪费资源了!于是有人发明了长轮询(Long Polling):客户端发请求,服务器不立刻回复,而是挂起连接,直到有数据才返回。这样看起来像“实时”,但实际上每次通信还是要建立一次HTTP连接。
// 长轮询伪代码
function poll() {
fetch('/chat/get-message')
.then(response => response.json())
.then(data => {
if (data.message) {
displayMessage(data.message);
}
// 无论有没有消息,都立刻发起下一次请求
poll();
});
}
poll();
1.2 为什么它“慢半拍”?
① 头部开销大
每次HTTP请求都要带一堆header(Cookie、User-Agent、认证信息等),哪怕服务器只回一个字符{"msg":"hi"},客户端也要付出一整条HTTP请求的代价。
② 连接建立延迟
TCP三次握手 + TLS握手(如果是HTTPS),光建立连接就要200-500ms。如果服务器没数据,客户端还要等更久。
③ 服务器压力大
假设1000个用户同时在线,每个用户每30秒发一次长轮询,服务器每秒要处理33个挂起的连接。一旦用户量到1万,服务器内存直接爆掉。
④ 网络抖动就卡顿
如果用户网络不好,请求超时,客户端会连续重试,造成请求风暴,服务器更扛不住。
📌 真实案例:某社交APP早期用长轮询做聊天功能,用户反馈“消息经常延迟5秒以上”。工程师排查发现,高峰期服务器有60%的CPU在处理HTTP连接的创建和销毁,而不是业务逻辑。
二、Websocket:一条“专线”打通实时通信
2.1 它是怎么工作的?
Websocket就像在客户端和服务器之间拉了一条专属电话线。一旦连接建立,双方可以随时互发消息,不需要再每次“打电话确认”。
(脑补图:客户端和服务器之间有一条持久的双向通道,消息随时可以发)
2.2 关键优势:双向、持久、低开销
① 一次性握手,长期有效
Websocket连接建立后,HTTP协议完成使命,后续通信用独立的帧格式,没有HTTP头部负担。
// Websocket简单示例
const ws = new WebSocket('wss://chat.example.com/ws');
ws.onopen = () => {
console.log('连接成功!');
};
ws.onmessage = (event) => {
console.log('收到消息:', event.data);
};
ws.send('你好,服务器!');
② 服务器可以主动推送
不再是客户端问“有没有消息”,而是服务器有消息直接推过来。延迟从几百毫秒降到几十毫秒。
③ 资源消耗极低
一个Websocket连接只占很小内存,10000个并发连接在普通服务器上也能扛得住。
三、性能对比:数字不会骗人
| 指标 | AJAX长轮询 | Websocket |
|---|---|---|
| 消息延迟 | 200-500ms(握手时间) | 20-50ms(推送即时) |
| 服务器连接数 | 高(每个轮询都占连接) | 低(一个用户一条连接) |
| 网络开销 | 大(每次都有HTTP头) | 小(帧头仅2-14字节) |
| 实时性 | 伪实时(取决于轮询间隔) | 真实时 |
| 实现复杂度 | 低 | 中 |
📊 数据说话:某直播平台从长轮询切换到Websocket后,服务器CPU负载下降70%,消息延迟从平均800ms降到50ms,用户体验评分提升40%。
四、为什么Websocket能“性能暴涨”?三个核心原因
原因一:去掉HTTP的“形式主义”
HTTP是请求-响应模式,每次通信都要“挂号、取号、排队、办事、离开”。Websocket是双向管道,直接“通话”。
HTTP轮询:请求 → 等待 → 响应 → 关闭 → 再请求 → 等待 → 响应...
Websocket:请求握手 → 连接建立 → 双向通信 → 手动关闭
原因二:减少TCP握手次数
长轮询每次都要TCP三次握手,Websocket只握一次手,后续所有消息复用同一个连接。
原因三:服务器资源释放更彻底
长轮询中,服务器挂起连接时会占用内存和线程;Websocket连接维护更轻量,且支持异步I/O(如Node.js的events模型),单机可支撑十万级连接。
五、Websocket不是银弹:什么时候该用,什么时候不该用
✅ 适合用Websocket的场景
- 实时聊天(微信、QQ网页版)
- 在线游戏(王者荣耀网页版)
- 实时协作(Google Docs、Figma)
- 股票行情推送
- 物联网设备数据上报
❌ 不适合用Websocket的场景
- 简单数据获取(用HTTP就够了,别搞复杂)
- 低频更新(每分钟一次的数据,轮询更简单)
- 兼容性要求极高(IE10以下不支持,但2024年了谁还用IE?)
六、落地建议:如何平滑迁移?
如果你现在的项目还在用长轮询,想切换到Websocket,别急着全量重写。试试这个渐进式方案:
// 1. 先检测浏览器是否支持Websocket
if ('WebSocket' in window) {
// 走Websocket
const ws = new WebSocket('wss://api.example.com/ws');
ws.onmessage = handleRealtimeMessage;
} else {
// 降级成长轮询
startLongPolling();
}
// 2. 心跳检测,保持连接活跃
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, 30000);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'pong') return; // 心跳响应,忽略
handleRealtimeMessage(data);
};
关键步骤:
- 前端检测支持情况,自动降级
- 后端提供两套接口,并行运行一段时间
- 观察Websocket的稳定性,再逐步切换
- 加上心跳机制,防止防火墙/代理断开空闲连接
七、写在最后:技术选型的本质是“权衡”
AJAX长轮询不是“坏”技术,它在Websocket普及之前立了大功。Websocket也不是“完美”技术,它增加了复杂度,需要处理重连、心跳、鉴权等问题。
选型的本质是:在当下场景,哪个技术能以最低成本满足用户需求。
如果你的聊天功能只有几百人在线,偶尔收发消息,长轮询完全够用。但如果要做万人同时在线的实时协作工具,Websocket几乎是唯一选择。
技术没有高低,只有合适与否。希望这篇文章能帮你更清楚地理解两者的差异,做出更明智的决策。
如果你有具体的项目场景,欢迎在评论区留言,我可以帮你分析该用哪种方案。
