欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發文檔 其他文檔  
 
網站管理員

瀏覽器節能機制導致WebSocket斷開連接的坑

admin
2024年11月7日 8:57 本文熱度 475

前言

最近,在使用 WebSocket(WS)連接時,我們遇到了頻繁斷開連接的問題,單個用戶每天會出現數百次。盡管使用 socket.io 的自動重連功能可以讓我們在斷開連接后迅速恢復連接,但并不能保證每次重連都能成功接收 WS 消息。因此,我們進行了多次調查和測試。最終,我們確定了問題的根本原因:瀏覽器的節能機制,它無意中成為了問題的罪魁禍首。

瀏覽器節能機制概述

瀏覽器的節能機制正成為前端開發者越來越重要的考慮因素。這些機制尤其會影響定時器的精度,直接影響前端應用的用戶體驗,在某些情況下甚至會影響可用性。

為了降低功耗并延長電池壽命,現代瀏覽器引入了節能機制。這些機制包括但不限于減少空閑標簽的 CPU 使用率、降低后臺 JavaScript 的執行頻率以及限制定時器的精度。雖然這些措施顯著提高了設備效率,但也給前端開發帶來了一些挑戰。

頻繁斷開連接分析

在查看 socket.io 服務器配置中的 pingTimeout 和 pingInterval 參數時,我們發現異常的 WS 心跳導致了重連。以下是詳細解釋:pingInterval(心跳間隔)

  • 默認值:25000(25 秒)
  • 此值用于心跳機制,用于定期檢查服務器與客戶端之間的連接是否仍然存活。服務器每隔 pingInterval 毫秒發送一個 ping 數據包,如果客戶端在 pingTimeout 毫秒內沒有回復 pong,服務器就認為連接已關閉。同樣,如果客戶端在 pingInterval + pingTimeout 毫秒內沒有收到服務器的 ping 數據包,那么客戶端也認為連接已關閉。在這兩種情況下,斷開連接的原因都將是:ping 超時。示例代碼如下:
socket.on("disconnect", (reason) => {
  console.log(reason); // "ping timeout"
});

使用像 1000(每秒一次心跳)這樣的小值會給服務器帶來一些負載,如果有數千個連接的客戶端,這可能會變得明顯。

pingTimeout(超時時間)

  • 默認值:20000(20 秒)
  • 見上文。
  • 注意事項:使用較小的值意味著暫時無響應的服務器可能會觸發大量客戶端重連。相反,使用較大的值意味著斷開的連接需要更長時間才能被檢測到(如果 pingInterval + pingTimeout 大于 60 秒,在 React Native 中可能會收到警告)。

在 WS 連接中,服務器和客戶端都必須保持恒定的心跳。如果任何一方停止,只要滿足以下任一條件,連接就會自動斷開:服務器發送 ping,如果客戶端在 pingTimeout 期間內沒有回復 pong,服務器認為連接已關閉;同樣,如果客戶端在 pingInterval + pingTimeout 期間內沒有收到服務器的 ping,客戶端也認為連接已關閉。

我們發現,在較高版本的 socket.io 中,服務器會定期發起 ping。相比之下,在 socket.io 2.X 中,內置的心跳機制是由客戶端發起的。當瀏覽器在后臺運行時,即使設置了每秒觸發一次的定時器,由于節能機制,它每分鐘只能觸發一次,超過了 pingInterval + pingTimeout 的設置。因此,日志顯示每分鐘都會有一次重連。

解決方案

1. 升級 socket.io 到最新版本:最新版本(4.x)由服務器發起心跳,避免了瀏覽器節能機制對定時器的影響。

2. 自定義 WS 心跳事件:為了盡量減少對現有業務邏輯的影響,另一種解決方案是使用自定義心跳事件。服務器定期發送 custom - ping。注意:斷開連接時銷毀定時器。雖然 socket.io 有內置心跳(2.x 中由客戶端發起,4.x 中由服務器發起),但自定義心跳有助于保持數據交換,防止自動斷開和重連。

客戶端代碼

io.on('custom - ping'function ({
  io.emit('custom - pong'Date.now())
})

服務器代碼

io.on('connection', (socket) => {
  console.log('New client connected');

  // 發送自定義 ping 消息
  const pingInterval = setInterval(() => {
    socket.emit('custom - ping'Date.now());
  }, 10000); // 每 10 秒

  // 監聽自定義 pong 消息
  socket.on('custom - pong', (data) => {
    console.log('Pong received:', data);
  });

  socket.on('disconnect', () => {
    clearInterval(pingInterval);
    console.log('Client disconnected');
  });
});

注意:斷開連接時銷毀定時器。

3. 使用 setTimeout:使用 setTimeout 時要謹慎,因為它仍然可能失去精度。示例代碼如下:

// 這個 setTimeout 會失去精度
let _cacheTs = Date.now()
const _setTimeoutFn = () => {
  console.log('setTimeout :>> 'Date.now() - _cacheTs);
  _cacheTs = Date.now()
  setTimeout(() => {
    _setTimeoutFn()
  }, 5000)
}
_setTimeoutFn()

在 setTimeout 中,執行函數棧由瀏覽器監控,類似于 setInterval,在后臺運行時其精度會降低。但是,以下方法可以避免節能機制的限制: - 客戶端代碼

// 監聽服務器發送的 custom - pong 事件
socket.on('custom - pong', onHeart)

const onHeart = () => {
  if (timer) {
    clearTimeout(pingTime.current)
  }
  timer = window.setTimeout(() => {
    socket.emit('custom - ping'Date.now())
  }, 5000)
}

// 服務器代碼
socket.on('custom - ping', ()=>{
  socket.emit('custom - pong'Date.now())
})

4. 使用 Web Workers:在 Web Worker 線程中啟動定時器不受瀏覽器節能機制的影響。

結論

隨著瀏覽器技術的發展,節能機制將變得更加精細,這給前端開發帶來了新的挑戰。理解并適應這些變化,并采用正確的策略來解決相關問題,對于開發高質量的前端應用至關重要。上述方法可以有效減輕或解決瀏覽器節能機制導致的定時器精度降低的影響,從而提升用戶體驗。


該文章在 2024/11/7 10:26:20 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業的專業生產管理軟件系統,系統成熟度和易用性得到了國內大量中小企業的青睞。
點晴PMS碼頭管理系統主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業務管理,結合碼頭的業務特點,圍繞調度、堆場作業而開發的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業的高效ERP管理信息系統。
點晴WMS倉儲管理系統提供了貨物產品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產管理,WMS管理系統,標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協同辦公管理系統。
Copyright 2010-2025 ClickSun All Rights Reserved