iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
JavaScript

可愛又迷人的 Web API系列 第 17

Day17. WebSocket 的處理訊息機制

  • 分享至 

  • xImage
  •  

WebSocket 是一個即時更新的服務,所以如果你的應用程式規模很大,或是客戶數量很多,就可能會碰到處理大量訊息的問題。這邊分享幾個處理訊息的機制,希望能對各位有所幫助。

批次處理

我們可以將多個訊息合併成一個批次進行處理,這樣能減少伺服器的負擔,也能提高系統效率。實作方式為,將在短時間內收到的多個消息合併成一個批次,然後一次性發送給伺服器。這樣可以減少網絡請求的次數,降低網絡延遲。

以下做一個簡單的聊天室例子,將十秒內收到的訊息一次傳給 WebSocket

const websocket = new WebSocket('wss://url');
let messageQueue = [];
const BATCH_INTERVAL = 10000; // 10秒

websocket.onopen = function() {
  console.log('WebSocket 連接已建立');
};

websocket.onmessage = function(event) {
  const messages = JSON.parse(event.data);
};

function sendMessage() {
  const messageInput = document.getElementById('messageInput');
  const message = messageInput.value;
  if (message) {
    messageQueue.push({ content: message });
    messageInput.value = '';
  }
}

setInterval(() => {
  if (messageQueue.length > 0) {
    const batch = messageQueue.splice(0, messageQueue.length);
    websocket.send(JSON.stringify(batch));
  }
}, BATCH_INTERVAL);

非同步處理

在處理 WebSocket 的訊息時,可以使用 JavaScript 的非同步來避免阻塞主線程。

websocket.onmessage = async function(event) {
  const messages = JSON.parse(event.data);
  for (const message of messages) {
    await processMessage(message);
  }
};

async function processMessage(message) {
  await new Promise(resolve => setTimeout(resolve, 100));
  console.log('Processed message:', message);
}

錯誤處理與重試

在前一篇文章有提到要立即掌握 WebSocket 的連線其實有困難性,我們有先透過 ping / pong 這種雙向心跳機制在後端做底層網路層的偵測處理。那如果是前端,可以怎麼設計呢?

前端通常會用重連機制主動去重連 WebSocket,因為有時候可能是網路問題,只要重連個兩、三次就能正常。此外如果可以,也要記錄錯誤日誌並返回錯誤,讓 Server 協助排查,並告知使用者相關的錯誤應對方式。

錯誤處理

以我為例,因為我們公司是後台系統,有時候需要瞭解客戶的操作以及當下碰到的問題,所以我請後端開發一隻錯誤日誌的 API,讓我能記錄如 WebSocket 連線錯誤時的訊息,並透過上述的非同步與批次處理,將錯誤日誌每隔一段時間發送到 API 利於排查。

async function processMessage(message) {
  try {
    await new Promise(resolve => setTimeout(resolve, 100));
    console.log('處理的訊息:', message);
  } catch (error) {
    console.error('error', error);
  }
}

重試機制

不管是重新發送訊息或是重新連線,都能用相同的概念做處理,我們可以自訂重試的次數以及間隔時間

async function processMessageWithRetry(message, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      await processMessage(message);
      return;
    } catch (error) {
      console.error(`嘗試第 ${i + 1} 次失敗:`, error);
      await new Promise(resolve => setTimeout(resolve, (i + 1) * 1000));
    }
  }
  console.error('全部的嘗試都失敗');
}

範例程式碼

https://mukiwu.github.io/web-api-demo/websocket-msg.html

小結

以上,有任何問題歡迎留言討論唷。


上一篇
Day16. 自己架個 WebSocket Server 玩玩吧
下一篇
Day18. 使用 Web Speech API 讓網頁聽得懂我們說的話
系列文
可愛又迷人的 Web API31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言