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

    瀏覽器節能機制導致Websocket斷連的坑

    admin
    2024年5月7日 17:20 本文熱度 198

    序言

    你踩過嗎?瀏覽器節能機制導致Websocket斷連的坑~~~

    近期,在使用WebSocket(WS)連接時遇到了頻繁斷連的問題,這種情況在單個用戶上每天發生數百次。盡管利用了socket.io的自動重連機制能夠在斷連后迅速恢復連接,但這并不保證每一次重連都能成功接收WS消息。因此,我們進行了一些的排查和測試工作。

    最終發現問題的根本原因:正是瀏覽器的節能機制,不經意間成為了這一問題的幕后黑手。

    ws1.png

    瀏覽器節能機制簡介

    瀏覽器的節能機制逐漸成為前端開發者需要關注的問題。特別是這些節能機制可能會對定時器的精度產生影響,這直接關系到前端應用的用戶體驗,在某些場景下甚至影響到用戶的使用。

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

    WS頻繁斷連原因分析

    查閱socket.io官網[1]服務端配置的pingTimeoutpingInterval兩個參數發現WS心跳異常時會導致重連,具體說明:

    WS連接中服務端和客戶端兩端必須一直保持心跳。如果有一端停止,則滿足如下條件之一就會自動斷連:

    • 服務器發送 ping,如果客戶端在毫秒內 pingTimeout 沒有用 pong 應答,則服務器認為連接已關閉。
    • 同樣,如果客戶端在毫秒內 pingInterval + pingTimeout 未收到來自服務器的 ping,則客戶端也會認為連接已關閉。

    看文檔發現其實高版本的socket.io是由服務端定時發起ping。而在socket.io 2.X的版本中內置的心跳機制是由客戶端定時發起。而瀏覽器在后臺運行時,即使你設置了一個每秒觸發的定時器,它也只能每分鐘觸發一次,超過了pingInterval + pingTimeout設置的時間,最后看到的日志是很有規律的每分鐘重連一次。在之前寫的這篇文章中也有相關的介紹《掌握Web Workers:徹底解鎖前端多線程編程的潛力》[2]

    WS頻繁斷連解決方法

    @升級socket.io到最新版本

    上面的截圖其實就是最新版本(4.x)的,升級后由服務器定時發起心跳。在服務端定時運行,避開了瀏覽器節能機制對定時器的影響

    @自定義WS心跳事件

    為了減小直接升級對已有業務的影響,目前使用的也是這種方案:在服務端自定義心跳事件,定時發送心跳custom-ping

    // 客戶端的CODE
    io.on('custom-ping', function () {
     io.emit('custom-pong', Date.now())
    })

    // 服務端CODE
    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');
     });
    });

    注意:斷連時一定要銷毀定時器

    其實,socket.io是有內置心跳的(2.x版本客戶端定時發起,4.x由服務端定時發起),自定義心跳的意義主要在于保持數據交換,在這個時間間隔內保持數據交換,socket就不會自動中斷重連。

    @使用setTimeout

    這里要注意使用setTimeout的姿勢,如果是直接這樣使用、依然會有精度問題。

    setTimeout丟失精度的情況:

    // 以下setTimeout仍然會丟失精度
    let _cacheTs = Date.now()
    const _setTimeoutFn = () => {
     console.log('setTimeout :>> ', Date.now() - _cacheTs);
     _cacheTs = Date.now()
     setTimeout(() => {
       _setTimeoutFn()
     }, 5000)
    }
    _setTimeoutFn()

    在setTimeout里面去執行一個函數棧會被瀏覽器監控到,會認為和setInterval一樣,其在后臺運行時會降低其定時精度。 但如果這樣可以避開節能機制的限制:

    setTimeout不丟失精度的情況:

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

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

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

    @使用Web-Workers

    在Web-Workers線程內發起定時不受瀏覽器節能機制的限制,相關示例在這篇文章里也有介紹《掌握Web Workers:徹底解鎖前端多線程編程的潛力》[3]

    @頁面;睿▽崪y無效)

    在后臺運行時也保持瀏覽器的活躍,用得最多的方式是在頁面隱藏一個循環播放的音頻 或者 使用nosleep.js

    const noSleepInstance = new NoSleep();
    document.addEventListener('click', function enableNoSleep() {
     document.removeEventListener('click', enableNoSleep, false);
     noSleepInstance.enable();
    }, false);

    實測,使用這種方式時,瀏覽器在后臺運行仍然存在定時器精度降低的問題。

    小結

    WS頻繁斷連的原因:

    1. 使用了低版本(2.x)的socket.io
    2. 客戶端每5秒定時發送 心跳
    3. 瀏覽器后臺運行時觸發節能機制限制了定時器的精度,由每5秒變成了實際的每分鐘執行一次
    4. 每分鐘執行一次遠大于socket.io設置的pingTimeout時間
    5. WS斷開連接
    6. socket.io內置的重連機制,立即重連成功
    7. 查看日志發現每分鐘重連一次。
      在實際排查中,是從第七步倒退排查發現是瀏覽器節能機制所引起的問題。。。

    總結

    隨著瀏覽器技術的發展,節能機制無疑會越來越完善,但與此同時也給前端開發帶來了新的挑戰。了解和適應這些變化,采用正確的策略來解決由此引起的問題,對于開發高質量的前端應用至關重要。通過上述方法,我們可以有效地緩解或解決瀏覽器節能機制對定時器精度降低帶來的影響,從而提升用戶體驗。

    參考資料

    [1]

    https://socket.io/zh-CN/docs/v4/server-options/#pinginterval: https://socket.io/zh-CN/docs/v4/server-options/#pinginterval

    [2]

    https://juejin.cn/post/7360890308845404200: https://juejin.cn/post/7360890308845404200

    [3]

    https://juejin.cn/post/7360890308845404200: https://juejin.cn/post/7360890308845404200


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

    日本高清无卡码一区二区久久|国产高清一区二区三区|高清无码一区二区三区四区|国产精品无码一区二区免费n