轮询与长轮询
轮询
客户端定时向服务器发送Ajax请求,服务器接到请求后,无论数据是否有变动,都返回响应信息并关闭连接。
优点:实现简单。
缺点:浪费带宽和服务器资源,新数据响应会有延迟。
长轮询
客户端发送请求,服务端在没有新的返回数据情况下不会立即响应,而会挂起,直到有数据变化或即将超时,返回响应信息。
优点:相对轮询,节约带宽。
缺点:在没有数据的时候在服务端挂起,会一直占用服务端资源。
轮询应用:
扫码登陆:pc端展示二维码,一直轮询问服务端二维码是否过期,或者用户已经用手机app扫码成功。
SSE(Server Send Event)服务器推送
一个客户端获取新的数据通常需要发送一个请求到服务器,也就是向服务器请求的数据。使用 server-sent 事件,服务器可以在任何时刻向我们的客户端推送数据和信息。这些被推送进来的信息可以在这个客户端上作为 Events + data 的形式来处理。
参考:https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
客户端
EventSource 类
使用 EventSource 类接口来完成请求。
//请求路由
let eventSource = new EventSource('/users');
// 监听数据返回事件
eventSource.addEventListener('users', function (e) {
console.log(`users`, e);
let users = JSON.parse(e.data);
})
参考:https://developer.mozilla.org/en-US/docs/Web/API/EventSource
服务端
头信息
router.get('/users', async (ctx, next) => {
//会一直向前端发送最新数据
let users = JSON.parse(fs.readFileSync('./data/users.json', 'utf-8'));
//需要设置EventSource对应的头信息
ctx.set('Content-Type', 'text/event-stream');
let eventStreamData = JSON.stringify(users);
//EventSource的数据格式:事件名称 和数据
ctx.body = `event: users\ndata:${eventStreamData}\n\n`;
})
WebSocket
WebSocket 是 HTML5 开始提供的一种在单个连接上进行全双工通讯的协议。
使用协议:ws ,其基于 HTTP 协议进行数据传输,但是会持久化链接和状态。
socket.io
可以参照官网实现聊天室功能。https://socket.io/
一个简单示例,可以实现浏览器多个tab传输数据
npm init -y
npm i express
npm i socket.io
html页面 index.html
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const form = document.getElementById('form');
const input = document.getElementById('input');
const messages = document.querySelector('#messages');
form.addEventListener('submit', function (e) {
e.preventDefault();
if (input.value) {
// 使用 websocket 向服务器发送数据
socket.emit('chat message - client', input.value);
input.value = '';
}
});
socket.on('chat message - server', (msg) => {
// 接收到 服务器 推送的 msg,并显示在页面聊天区域中
console.log(msg);
const item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
})
</script>
</body>
服务端
node服务 index.js
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
// 监听事件
// 每一个独立的客户端和服务器建立连接以后,会生成一个socket对象,
//该对象保存了两个独立连接的相关信息和对应的方法,当前这个客户端与服务器的通信都是基于给对象来进行的
let sockets = [];
io.on('connection', (socket) => {
console.log(`有客户端通过websocket连接了`);
sockets.push(socket);
// 监听 chat message 事件
socket.on('chat message - client', (msg) => {
console.log('message: ' + msg);
// 对当前这个 socket 进行 emit
socket.emit('chat message - server', msg);
// 对除了自己全局广播消息
socket.broadcast.emit('chat message - server', msg);
})
})
server.listen(3000, () => {
console.log('listening on *:3000');
});
可以通过WS筛选查看链接详情

image.png