即時網頁技術簡介 (Polling, Long-Polling, Server Sent Events, WebSocket) 從前後端看即時網頁通訊技術

Lin Yen-Cheng on 2019-07-04 4 min. read

通訊方式簡介

從雙方通訊的方式可以分成下面三種:

  • 單工:訊號只在一個方向上進行傳遞,像是郵差寄信。
  • 半雙工:可以切換方向的單工通訊,像是小時候玩的對講機。
  • 全雙工:現在的即時通訊,雙方都可以同時接收或是傳送訊息。

即時網頁技術

要達到即時,可以透過以下手段:

  • Polling: 前端向 Server 發出 Request,如果沒拿到想要的資料,就再重發,伺服器附載較重。
  • Long-Polling: Client 發 Request 給 Server,Server 送 Response 給 Client 後才斷開連線,Client 收到,再發 Request 給 Sevrer,占用連線數。
  • Server Sent Events: 由瀏覽器幫我們處理,前端實作上只要監聽相關的事件就可以了。
  • WebSocket: 解決了單向請求的問題,但很多情況不一定需要用到雙向通訊,從上面的特性看起來,伺服器也因為使用的情境不同,最佳化時會有差異。
  • Forever Frame: IE only,嵌入一個 IFrame,連向 SignalR 提供的內容。

網頁端

在網頁端提供支援較也常用的解決方案有以下四種:

  • SignalR: 微軟的解決方案,封裝了所有的即時網頁技術,包含支援 IE。
  • Socket.IO: node.js 解決方案,封裝了 polling 及 websocket。
  • MQTT: 適合輕量級物聯網使用,封包較小可以支援大量的 client。
  • Service Worker: 離線推播,獨立 Thread 無法操作 dom,透過 PushManager 可以使用推播。

Server Sent Events

直接上範例程式碼。

// Server
let clients = [];
const server = express();

function sendEventsToClients() {
  clients.forEach((c) => {
    c.res.write(`change`);
  });
}

async function modify(req, res) {
  res.json({ status: 1 });
  return sendEventsToClients();
}

server.get("/modify", modify);
server.get("/listen", (req, res) => {
  const { clientId } = req.query;
  const headers = {
    "Content-Type": "text/event-stream",
    Connection: "keep-alive",
    "Cache-Control": "no-cache",
  };
  res.writeHead(200, headers);
  res.write("");
  const newClient = {
    id: clientId,
    res,
  };
  clients.push(newClient);
  req.on("close", () => {
    clients = clients.filter((c) => c.id !== clientId);
  });
});

// client
const events = new EventSource("/listen?clientId=test");
events.onmessage = (event) => {
  if (event.data) console.log(event.data);
};

Socket.IO

是一個 event-based 全雙工的通訊函式庫,事件驅動這個部分是最容易出包的地方,當我們在和 react 專案整合在一起的時候,就需要去注意事件是不是有和畫面的渲染綁在一起,意思就是說不可以每渲染一次,我就重新建立連結、重新監聽事件、重新發出訊息,這樣一來記憶體很快就會用完,處理器也根本來不及處理。


喜歡這篇文章,請幫忙拍拍手喔 🤣

share