- Published on
前端实现实时通信的方法?如何选择?
- Authors

- Name
- 叫我小N就好啦
- GitHub
- @MinorN
前端实现实时通信的方法?如何选择?
首先得知道有哪些通信方法,目前主要有以下几种方法:短轮询、长轮询、SSE、Websocket
短轮询
基本原理
短轮询就是定期向服务器发送请求来获取最新的实时数据,短轮询的特点就是不会保持持久连接
过程:
- 客户端发送请求
- 服务端响应对应的请求,如果有新数据,则返回,没有新数据则返回为空或者约定一个空数据的状态码
- 客户端处理响应
- 重复请求
- 循环以上步骤
下面是一个简单的短轮询实例
function loop() {
setInterval(() => {
fetch('http://xxx.com/test')
.then((data) => {
// 处理数据
})
.catch((e) => {
// 上报错误信息等
console.log(e)
})
}, 5 * 1000)
}
loop()
优缺点
优点:
- 简单,容易实现,不需要特殊的支持
- 兼容性好
缺点
- 效率低,需要频繁向后端发送请求,如果用户量大,可能会增加服务器压力
- 实时性较差,每次请求都得等待固定时间
总结
总体来说,什么时候使用短轮询呢?一些实时性要求不高的场景,且对服务器压力要求相对较低
长轮询
长轮询是基于短轮询的改进,短轮询不会保持持久连接,但是长轮询向服务器发送的是一个持久连接的请求,当有新数据时,立即返回响应
基本原理
- 客户端发送请求
- 服务端处理请求
- 响应返回,如果服务器有新数据,立即返回响应,并关闭连接;如果没有,则等待新数据到达或者超时
- 客户端处理响应,需要处理超时的情况,当接收到新数据后,立即再次发送一个长轮询的请求
- 循环以上步骤
由于需要服务器支持长连接请求,所以需要服务端支持,以下是客户端的简单实现
funtcion loop(){
setInterval(()=>{
fetch('http://xxx.com/test').then((data)=>{
// 这里要处理超时的情况
}).catch((e)=>{
// 上报
console.log(e)
})
},1000)
}
loop()
以下是服务端的简单实现
const data = 'init'
app.get('/test', (req, res) => {
const timeout = 10
const startTime = new Date().getTime()
const checkData = () => {
// 检查数据是否发生变化或特定事件是否发生,这里假设直接使用一个全局变量 data 来模拟数据的变化
if (data !== 'init') {
res.json({ data: data })
} else if (new Date().getTime() - startTime > timeout * 1000) {
res.json({ data: null }) // 如果超时,则返回空响应
} else {
setTimeout(checkData, 1000) // 等待一段时间后再次检查
}
}
checkData()
})
优缺点
优点
- 实时性好,可以立即返回新数据,同时实现简单
- 兼容性好
缺点:
- 资源存在浪费现象,因为长轮询会让服务器维持大量的连接,如果没有数据,必须等到超时才能够关闭
- 不支持全双工通信,也就是只能服务端向客户端发送信息
SSE
基本原理
SSE 是服务器推送时间,是一种服务器主动向客户端推送消息的技术,SSE 是 HTML5 中一个与通信有关的 API,主要由服务端与浏览器的通信协议和浏览器提供的 EventSource 对象两部分组成,SSE 允许服务端实时地向客户端推送事件流
SSE 很简单,只需要在响应头加上
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
以下是客户端的简单实现
const eventSource = new EventSource('http://xxx.com/test')
eventSource.onmessage = function (event) {
const data = JSON.parse(event.data)
}
eventSource.onerror = function (error) {
console.log(error)
}
以下是服务端的简单实现
let clients = []
app.get('test', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream')
res.setHeader('Cache-Control', 'no-cache')
res.setHeader('Connection', 'keep-alive')
const clientId = Date.now()
clients.push({ id: clientId, res })
res.write('xxxx') // 初始化消息
req.on('close', () => {
// 断开连接
clients = clients.filter((client) => client.id !== clientId)
})
})
优缺点
优点:
- 实时性更加迅速
- 轻量级,因为基于的是标准的 HTTP 协议
- 简单易用
缺点:
- 单向通行
- 兼容性不如前两种方式
- 某些情况下,连接可能会断开,需要重新连接
应用场景
- 即时的通知、提醒
- 实时数据更新
- 在线游戏
- 监控报警
- 在线交易系统
- 客服
Websocket
基本原理
Websocket 是一种客户端和服务端之间双向通信的技术,它通过建立一个持久的连接来实现实时、高效的通信
特点:
- 支持双向通信,可以发送文本、二进制数据
- 数据格式轻量,性能开销小
- 没有同源限制
优缺点
优点
- 实时性高,性能高
- 跨平台支持
- 持久连接
- 双向通信
缺点
- 长时间连接可能会受到攻击
- 状态管理复杂
应用场景
- 在线聊天
- 实时协作编辑
- 实时游戏
- 监控告警