小弟最近因缘际会下接触了聊天室,后来查阅了一下目前有 Polling、WebSocket 与 SSE 三种实作方法,这边比较一下各个方法的差异与特性
Polling
Polling 中文翻译为轮询,你可能没听过,但是你一定用过,其实说白了就是不断的去呼叫 function
而已,其中又分为 Polling
与 Long Polling
,以下做介绍
Polling(轮询)
Polling 每隔固定的时间就呼叫一次 function
function shortPolling() { console.log("Short Polling");}setInterval(shortPolling, 1000);
Long Polling(长轮询)
Long Polling 则是在 function
返回后再次呼叫该 function
function longPolling() { setTimeout(function() { console.log("Long Polling"); longPolling(); }, 1000);}longPolling();
分析
优点:实现容易、支援度高缺点:非常耗资源、无法即时响应WebSocket
WebSocket 是一种网路传输协定,在 WebSocket API
中,Client 与 Server 只需要完成一次交握,两者之间就可以建立永续性的连接,它让资料能够更有效率的做交换,后端这边使用 ws 做Demo
Demo(后端)
// 载入 wsconst WebSocket = require("ws");// 设定 WebSocketconst wss = new WebSocket.Server({ port: 3000 });// WebSocket APIwss.on("connection", function connection(ws) { // 接收 Client 端讯息 ws.on("message", function incoming(message) { console.log(message); }); // 传送 Server 端讯息 ws.send("我是 Server");});
Demo(前端)
// WebSocket APIconst ws = new WebSocket("ws://localhost:3000");// 连接 API 并传送 Client 端讯息ws.onopen = function() { ws.send("我是 Client");};// 接收 Server 端讯息ws.onmessage = function(e) { console.log(e.data);};
分析
优点:节省资源、优异的即时性缺点:伺服器维护成本较高、支援度较其他低踩雷小补充
如果前端需要订阅某个 Channel 写法如下
const ws = new WebSocket("ws://localhost:3000");ws.onopen = function() { // 增加以下两行,ChannelName 改为订阅的频道名称 const subscribe = { command: 'subscribe', identifier: '{"channel":"ChannelName"}' } ws.send(JSON.stringify(subscribe))};ws.onmessage = function(e) { console.log(e.data);};
SSE(Server-Sent Events)
SSE 是 HTML5 标準的 API,他在 Client 连接至 Server 后,透过一般的 http 协定主动将资料推送至 Client,并且不会断开连接,使用时须要按照规定的格式,先我们先认识一下写法
资料格式
前方加上 data:
,资料结尾须加上 \n\n
,若只有 \n
为换行
// 单行data: message\n\n// 多行data: first message\ndata: second message\n\n
重新连线时间
当连线意外中断后,如果有设定 retry:
时间,则时间一到会重新连线
// 中断连线后5秒重新连结retry: 5000\n
自订事件名称
指定事件名称时可使用 event:
来做,预设为 message
event: myEvent\n
Demo(后端)
这边 Demo 使用 express 与 cors
// 载入 express 与 corsconst express = require("express");const cors = require("cors");const app = express();// 使用 cors 套件app.use(cors());// 设定 SSE APIapp.get("/", function(req, res) { // 设定 SSE header res.header({ "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" }); // 设定重新连接时间 res.write("retry: 1000\n"); let data = { name: "ares", time: null }; // 每隔3秒传送一次资料 setInterval(() => { defaultEvent(); myEvent(); }, 3000); // 预设事件 - message function defaultEvent() { data.time = new Date(); res.write(`data: ${JSON.stringify(data)}\n\n`); } // 自订事件 - myEvent function myEvent() { data.time = new Date(); res.write("event: myEvent\n"); res.write(`data: ${JSON.stringify(data)}\n\n`); }});// 监听 3000 portapp.listen(3000);
Demo(前端)
// SSE APIconst sse = new EventSource("http://localhost:3000");// 连接时触发此事件sse.addEventListener("open", e => console.log("开启连接"));// 连线中断或其他错误触发此事件sse.addEventListener("error", e => console.log("关闭连接"));// 预设事件 - messagesse.addEventListener("message", e => console.log("message:", JSON.parse(e.data)));// 自订事件 - myEventsse.addEventListener("myEvent", e => console.log("myEvent:", JSON.parse(e.data)));// 设定十秒后关闭连接setTimeout(() => { sse.close();}, 10000);
分析
优点:节省资源、支援度高缺点:无法即时响应结语
看过这些方法后发现,WebSocket
适合拿来做线上游戏、聊天室,只是支援度较其他低,而 Polling
适合功能简单资源度低的地方,SSE
基本上就是 Polling 的升级版,适合拿来做新闻页面、即时股价的应用,各有各的使用情境~