短轮询、长轮询与长连接详解及 Axios 代码实现
1. 短轮询(Short Polling)
原理
客户端通过 定时器(如每 5 秒) 主动向服务器发送请求,无论数据是否有更新。
特点:
• ✅ 实现简单,兼容所有 HTTP 服务
• ❌ 频繁无效请求,资源浪费严重
• ❌ 实时性差(依赖轮询间隔)
适用场景:静态数据低频更新(如天气预报、配置拉取)。
// 短轮询代码(Axios)
let isPollingActive = true;
const startShortPolling = async () => {
while (isPollingActive) {
try {
const response = await axios.get('/api/short-poll');
console.log('短轮询数据:', response.data);
await new Promise(resolve => setTimeout(resolve, 5000)); // 5秒间隔
} catch (error) {
console.error('短轮询失败:', error);
isPollingActive = false; // 出错时停止
}
}
};
// 启动轮询
startShortPolling();
// 停止轮询
const stopShortPolling = () => {
isPollingActive = false;
};
2. 长轮询(Long Polling)
原理
客户端发送请求后,服务器会 挂起连接直到数据更新或超时(如 30 秒)。客户端收到响应后立即重新发起请求。
特点:
• ✅ 减少无效请求,实时性优于短轮询
• ❌ 需要服务器支持长时挂起
• ❌ 客户端需处理超时和重连
适用场景:实时聊天、订单状态跟踪等中等实时性需求。
// 长轮询代码(Axios + AbortController)
const abortController = new AbortController();
const startLongPolling = async () => {
try {
const response = await axios.get('/api/long-poll', {
signal: abortController.signal, // 绑定中断控制器
timeout: 30000 // 30秒超时
});
console.log('长轮询数据:', response.data);
startLongPolling(); // 立即发起下一次请求
} catch (error) {
if (axios.isCancel(error)) {
console.log('长轮询被手动终止');
} else {
console.error('长轮询错误:', error);
setTimeout(startLongPolling, 1000); // 1秒后重试
}
}
};
// 启动长轮询
startLongPolling();
// 终止长轮询
const stopLongPolling = () => {
abortController.abort();
};
3. 长连接(Long Connection)
原理
基于 WebSocket(双向通信) 或 SSE(Server-Sent Events,单向推送) 的持久连接,服务器可主动推送数据。
特点:
• ✅ 实时性最高,无频繁请求开销
• ❌ 需要协议和服务器支持(如 WebSocket 需 ws://
)
• ❌ 实现复杂度较高
3.1 WebSocket(双向通信)
// 浏览器原生 API(Axios 不适用)
const socket = new WebSocket('wss://your-websocket-server');
socket.addEventListener('open', () => {
socket.send('连接已建立');
});
socket.addEventListener('message', (event) => {
console.log('收到消息:', event.data);
});
3.2 SSE(单向推送)
// 浏览器原生 API(Axios 不适用)
const eventSource = new EventSource('/api/sse');
eventSource.onmessage = (event) => {
console.log('SSE 数据:', event.data);
};
eventSource.onerror = () => {
console.error('SSE 连接异常');
};
对比总结
方式 | 实时性 | 资源消耗 | 实现复杂度 | 协议依赖 |
---|---|---|---|---|
短轮询 | 低 | 高(频繁请求) | 简单 | HTTP 1.1+ |
长轮询 | 中 | 中(减少请求) | 中等 | 需服务器支持挂起 |
WebSocket | 高 | 低(持久连接) | 复杂 | WebSocket 协议 |
SSE | 高 | 低(单向推送) | 中等 | HTTP/2+ |
实际开发建议
-
短轮询
• 使用setTimeout
或setInterval
控制频率
• 添加请求锁(如isPollingActive
)避免并发冲突 -
长轮询
• 使用 AbortController 精准控制请求中断
• 添加重试机制(如指数退避setTimeout(retry, 1000 * 2^attempt)
) -
长连接
• 高频双向通信选 WebSocket(如在线游戏)
• 单向推送选 SSE(如新闻实时播报)
• 使用 Socket.io 库简化 WebSocket 开发
// 长轮询重试逻辑示例(指数退避)
let retryCount = 0;
const MAX_RETRIES = 5;
const fetchWithRetry = async () => {
try {
const response = await axios.get('/api/data');
retryCount = 0; // 重置重试计数器
return response.data;
} catch (error) {
if (retryCount < MAX_RETRIES) {
retryCount++;
await new Promise(resolve =>
setTimeout(resolve, 1000 * Math.pow(2, retryCount))
);
return fetchWithRetry();
} else {
throw new Error('超过最大重试次数');
}
}
};
注意事项
• 服务端适配:长轮询需服务器支持挂起请求(如 Node.js 的 keep-alive
)
• 性能监控:短轮询频繁请求可能触发服务器限流
• 浏览器兼容性:SSE 不支持 IE,WebSocket 需现代浏览器