iT邦幫忙

3

JavaScript - Polling、WebSocket 與 SSE 介紹

Ares 2020-03-20 12:39:173062 瀏覽

小弟最近因緣際會下接觸了聊天室,後來查閱了一下目前有 Polling、WebSocket 與 SSE 三種實作方法,這邊比較一下各個方法的差異與特性

Polling

Polling 中文翻譯為輪詢,你可能沒聽過,但是你一定用過,其實說白了就是不斷的去呼叫 function 而已,其中又分為 PollingLong 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(後端)

// 載入  ws
const WebSocket = require("ws");

// 設定 WebSocket
const wss = new WebSocket.Server({ port: 3000 });

// WebSocket API
wss.on("connection", function connection(ws) {
  // 接收 Client 端訊息
  ws.on("message", function incoming(message) {
    console.log(message);
  });
  // 傳送 Server 端訊息
  ws.send("我是 Server");
});

Demo(前端)

// WebSocket API
const 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\n
data: second message\n\n

重新連線時間

當連線意外中斷後,如果有設定 retry: 時間,則時間一到會重新連線

// 中斷連線後5秒重新連結
retry: 5000\n

自訂事件名稱

指定事件名稱時可使用 event: 來做,預設為 message

event: myEvent\n

Demo(後端)

這邊 Demo 使用 expresscors

// 載入 express 與 cors
const express = require("express");
const cors = require("cors");
const app = express();

// 使用 cors 套件
app.use(cors());

// 設定 SSE API
app.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 port
app.listen(3000);

Demo(前端)

// SSE API
const sse = new EventSource("http://localhost:3000");

// 連接時觸發此事件
sse.addEventListener("open", e => console.log("開啟連接"));

// 連線中斷或其他錯誤觸發此事件
sse.addEventListener("error", e => console.log("關閉連接"));

// 預設事件 - message
sse.addEventListener("message", e =>
  console.log("message:", JSON.parse(e.data))
);

// 自訂事件 - myEvent
sse.addEventListener("myEvent", e =>
  console.log("myEvent:", JSON.parse(e.data))
);

// 設定十秒後關閉連接
setTimeout(() => {
  sse.close();
}, 10000);

分析

  • 優點:節省資源、支援度高
  • 缺點:無法即時響應

結語

看過這些方法後發現,WebSocket 適合拿來做線上遊戲聊天室,只是支援度較其他低,而 Polling 適合功能簡單資源度低的地方,SSE 基本上就是 Polling 的升級版,適合拿來做新聞頁面即時股價的應用,各有各的使用情境~


尚未有邦友留言

立即登入留言