最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript檢測網(wǎng)絡連接狀態(tài)以及網(wǎng)絡測速的具體方案

 更新時間:2026年03月19日 08:46:02   作者:程序員小寒  
在實際開發(fā)項目中,有時候需要拿到用戶網(wǎng)絡狀態(tài),然后根據(jù)用戶的網(wǎng)絡情況進行優(yōu)化,但在實際開發(fā)中,我們一般會劃分成斷網(wǎng)、弱網(wǎng)、強網(wǎng)三個等級,并針對等級進行優(yōu)化,那么 JavaScript 中如何檢測用戶網(wǎng)絡狀態(tài)呢?下面小編為大家詳細說說

引言

在實際開發(fā)項目中,有時候需要拿到用戶網(wǎng)絡狀態(tài),然后根據(jù)用戶的網(wǎng)絡情況進行優(yōu)化。常見的網(wǎng)絡狀態(tài)有離線 offline、WiFi、2G/3G、4G、5G 等,但在實際開發(fā)中,我們一般會劃分成斷網(wǎng)、弱網(wǎng)、強網(wǎng)三個等級,并針對等級進行優(yōu)化。比如在視頻播放時,可以根據(jù)不同網(wǎng)絡情況給用戶分別默認播放不同清晰度的視頻(高清、標清、流暢等)。

那么 JavaScript 中如何檢測用戶網(wǎng)絡狀態(tài)呢?

1、網(wǎng)絡狀態(tài):在線 online Or 離線 offline?

HTML5 規(guī)范提供了 navigator.onLine 來拿到瀏覽器的在線狀態(tài)。該屬性返回一個布爾值,true 表示在線,false 表示離線。同時提供了 onlineoffline 事件,通過監(jiān)聽這兩個事件,可以動態(tài)監(jiān)聽到網(wǎng)絡連接狀態(tài)變化。

// 監(jiān)聽網(wǎng)絡連接狀態(tài)
window.addEventListener('online', () => {
  console.log('網(wǎng)絡已連接');
  // 觸發(fā)數(shù)據(jù)同步...
});

window.addEventListener('offline', () => {
  console.log('網(wǎng)絡已斷開');
  // 進入離線模式...
});

// 實時獲取當前狀態(tài)
console.log('當前網(wǎng)絡狀態(tài):', navigator.onLine ? '在線' : '離線');

但是 navigator.onLine 有一定的局限性,比如在某些情況下,網(wǎng)絡是連接的,它也返回 true 了,但實際上無法訪問你的后端 API:

  • WiFi連接了但無互聯(lián)網(wǎng)訪問(比如公共圖書館需要登錄認證的公共 WiFi)。
  • 網(wǎng)絡延遲極高(理論上在線,但請求超時)。
  • DNS解析失敗。

我們需要更加準確的判斷用戶此刻是否網(wǎng)絡能正常訪問服務端,這就需要做心跳檢測。

2、心跳檢測

顧名思義,心跳檢測就像人的心跳一樣,每隔一段時間跳動一下,告訴外界"我還活著"。它是一種用于判斷連接對端(如服務器或客戶端)是否存活的機制。它常常用于 WebSocket 連接,用來解決非正常關(guān)閉造成的"死連接"問題。我們這里可以借用它檢測客戶端“是否存活”的能力,來判斷客戶端的網(wǎng)絡是否正常訪問后端 API。

心跳檢測客戶端代碼:

// client.js
class NetworkMonitor {
  constructor(options = {}) {
    this.options = {
      pingUrl: '/api/ping',        // 心跳檢測接口
      interval: 30000,              // 30秒檢測一次
      timeout: 5000,                 // 5秒超時
      onStatusChange: null,          // 狀態(tài)變化回調(diào)
      ...options
    };
    
    this.isOnline = navigator.onLine;  // 當前網(wǎng)絡狀態(tài)
    this.checking = false;              // 是否正在檢測
    this.timer = null;                  // 定時器
    this.consecutiveFailures = 0;       // 連續(xù)失敗次數(shù)
    this.maxFailures = 2;                // 最大允許失敗次數(shù)
    
    this.init();
  }
  
  init() {
    // 監(jiān)聽瀏覽器原生事件
    window.addEventListener('online', () => this.handleBrowserOnline());
    window.addEventListener('offline', () => this.handleBrowserOffline());
    
    // 啟動心跳檢測
    this.startHeartbeat();
  }
  
  startHeartbeat() {
    this.stopHeartbeat();
    this.timer = setInterval(() => this.checkNetwork(), this.options.interval);
    // 立即執(zhí)行一次
    this.checkNetwork();
  }
  
  stopHeartbeat() {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
  }
  
  async checkNetwork() {
    if (this.checking) return;
    
    this.checking = true;
    const startTime = Date.now();
    
    try {
      // 使用fetch發(fā)起一個輕量級請求
      const response = await fetch(this.options.pingUrl, {
        method: 'HEAD',  // 只獲取頭部,減少數(shù)據(jù)傳輸
        mode: 'no-cors', // 如果跨域且無需讀取響應
        cache: 'no-cache',
        headers: {
          'X-Network-Check': 'ping'
        }
      });
      
      // 請求成功
      this.handleSuccess();
      
    } catch (error) {
      // 請求失?。ǔ瑫r、網(wǎng)絡錯誤等)
      this.handleFailure();
    } finally {
      this.checking = false;
    }
  }
  
  handleSuccess() {
    // 重置失敗計數(shù)
    this.consecutiveFailures = 0;
    
    // 如果之前是離線,現(xiàn)在變?yōu)樵诰€
    if (!this.isOnline) {
      this.setOnlineStatus(true);
    }
  }
  
  handleFailure() {
    this.consecutiveFailures++;
    
    // 連續(xù)失敗達到閾值,判定為離線
    if (this.consecutiveFailures >= this.maxFailures && this.isOnline) {
      this.setOnlineStatus(false);
    }
  }
  
  handleBrowserOnline() {
    // 瀏覽器說在線了,但我們?nèi)孕栩炞C真正的API可達性
    console.log('瀏覽器報告網(wǎng)絡已連接,開始驗證...');
    this.checkNetwork();
  }
  
  handleBrowserOffline() {
    // 瀏覽器明確說離線,直接更新狀態(tài)
    this.setOnlineStatus(false);
  }
  
  setOnlineStatus(status) {
    if (this.isOnline !== status) {
      this.isOnline = status;
      
      console.log(`網(wǎng)絡狀態(tài)變更為: ${status ? '在線' : '離線'}`);
      
      // 觸發(fā)回調(diào)
      if (this.options.onStatusChange) {
        this.options.onStatusChange(status);
      }
      
      // 觸發(fā)自定義事件,方便其他地方監(jiān)聽
      window.dispatchEvent(new CustomEvent('network-status-change', {
        detail: { isOnline: status }
      }));
    }
  }
  
  // 手動觸發(fā)一次檢測
  async checkNow() {
    return this.checkNetwork();
  }
  
  // 銷毀
  destroy() {
    this.stopHeartbeat();
    window.removeEventListener('online', this.handleBrowserOnline);
    window.removeEventListener('offline', this.handleBrowserOffline);
  }
}

// 使用示例
const monitor = new NetworkMonitor({
  pingUrl: 'https://your-api.com/api/ping',
  interval: 15000,  // 15秒檢測一次
  timeout: 3000,
  onStatusChange: (isOnline) => {
    if (isOnline) {
      // 網(wǎng)絡恢復,觸發(fā)數(shù)據(jù)同步
      syncWithServer();
      showToast('網(wǎng)絡已恢復,正在同步數(shù)據(jù)...');
    } else {
      // 網(wǎng)絡斷開,進入離線模式
      enableOfflineMode();
      showToast('網(wǎng)絡已斷開,進入離線模式');
    }
  }
});

心跳檢測服務端代碼:

// server.js
const express = require('express');
const app = express();
const port = 3000;

// 心跳檢測接口
app.head('/api/ping', (req, res) => {
  // 可選:記錄心跳日志
  console.log(`[${new Date().toISOString()}] 收到心跳檢測請求 from ${req.ip}`);
  
  // 可選:檢查自定義頭
  if (req.headers['x-network-check'] === 'ping') {
    console.log('網(wǎng)絡健康檢查請求');
  }
  
  // 只需返回 200 狀態(tài)碼即可
  res.status(200).end();
});

// 如果需要 GET 也支持(某些場景可能需要)
app.get('/api/ping', (req, res) => {
  // 可以返回一些輕量級數(shù)據(jù)
  res.json({ 
    status: 'ok', 
    timestamp: Date.now(),
    message: 'success' 
  });
});

// 啟動服務器
app.listen(port, () => {
  console.log(`網(wǎng)絡監(jiān)控服務運行在 http://localhost:${port}`);
});

3、網(wǎng)速檢測

3.1 navigator.connection

HTML5 規(guī)范提供了 navigator.connection 可以獲取網(wǎng)絡類型 effectiveType 和網(wǎng)絡下行速度 downlink。

console.log("網(wǎng)絡狀態(tài):" + navigator.connection.effectiveType); // 比如:4g/3g/2g
console.log("網(wǎng)絡下行速度:" + navigator.connection.downlink  + "MB/S"); // 比如:10MB/S

navigator.connection 存在兩個問題,第一個是兼容性很差,像 Edge、FirefoxSafari 這種主流瀏覽器都不支持。

第二個是數(shù)據(jù)不準確,與一些測速器的結(jié)果有一定的偏差。基于這兩個問題,實際項目中不會采用 navigator.connection 方案。

3.2 圖片測速法

圖片測速法就是通過客戶端加載圖片,拿到圖片大小和加載時間,進而算出用戶的網(wǎng)速,其具體步驟如下:

  1. 加載兩張圖片,一張極小的(比如 1x1像素),一張稍大的(比如 2x2像素)。
  2. 記錄圖片請求開始時間,以及圖片 onLoad 完成的時間。
  3. 計算速度:圖片大小 / 加載時間 = 網(wǎng)速
  4. 取平均值,把兩個數(shù)據(jù)取個平均值,目的是減少誤差。

小結(jié)

  1. 瀏覽器可以通過 navigator.onLine 接口拿到瀏覽器的在線狀態(tài),并通過監(jiān)聽 onlineoffline 事件監(jiān)聽網(wǎng)絡變化。
  2. 由于 navigator.onLine 存在一定的局限性,比如無法識別到 WiFi 連接了但無互聯(lián)網(wǎng)訪問、網(wǎng)絡延遲極高、DNS 解析失敗等情況,我們還需要通過心跳檢測方案來判斷客戶端是否能正常訪問后端 API。
  3. navigator.connection 雖然能拿到用戶的網(wǎng)絡下行速度 downlink,但 connection 接口存在兼容性和數(shù)據(jù)不準的問題,所以我們需要用圖片測速法來更加準確地拿到用戶網(wǎng)速情況。

以上就是JavaScript檢測網(wǎng)絡連接狀態(tài)以及網(wǎng)絡測速的具體方案的詳細內(nèi)容,更多關(guān)于JavaScript檢測網(wǎng)絡連接狀態(tài)及測速的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JS實現(xiàn)非首屏圖片延遲加載的示例

    JS實現(xiàn)非首屏圖片延遲加載的示例

    下面小編就為大家分享一篇用JS實現(xiàn)非首屏圖片延遲加載的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • javascript實例--教你實現(xiàn)撲克牌洗牌功能

    javascript實例--教你實現(xiàn)撲克牌洗牌功能

    我們一般都會按照順序把隨機摸過來的牌從小到大的順序在手上理整齊(記得小時候打牌兩副牌手都抓不過來),這篇隨筆就是想通過實現(xiàn)這個功能來熟悉下js中排序數(shù)組等相關(guān)知識。
    2014-05-05
  • JavaScript獲取短信驗證碼(周期性)

    JavaScript獲取短信驗證碼(周期性)

    這篇文章主要為大家詳細介紹了JavaScript周期性獲取短信驗證碼的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • JS forEach和map方法的用法與區(qū)別分析

    JS forEach和map方法的用法與區(qū)別分析

    這篇文章主要介紹了JS forEach和map方法的用法與區(qū)別,結(jié)合實例形式分析了forEach和map方法的功能、原理、使用方法及相關(guān)操作注意事項,需要的朋友可以參考下
    2019-02-02
  • 詳解webpack引用jquery(第三方模塊)的三種辦法

    詳解webpack引用jquery(第三方模塊)的三種辦法

    這篇文章主要介紹了詳解webpack引用jquery(第三方模塊)的三種辦法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • 微信小程序 接入騰訊地圖的兩種寫法

    微信小程序 接入騰訊地圖的兩種寫法

    這篇文章主要介紹了微信小程序 接入騰訊地圖的兩種寫法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • 同步異步動態(tài)引入js文件的幾種方法總結(jié)

    同步異步動態(tài)引入js文件的幾種方法總結(jié)

    下面小編就為大家?guī)硪黄疆惒絼討B(tài)引入js文件的幾種方法總結(jié)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • js尾調(diào)用優(yōu)化的實現(xiàn)

    js尾調(diào)用優(yōu)化的實現(xiàn)

    這篇文章主要介紹了js尾調(diào)用優(yōu)化的實現(xiàn),尾調(diào)用(Tail Call)是函數(shù)式編程的一個重要概念,本文介紹它的含義和用法。感興趣的可以了解一下
    2019-05-05
  • js實現(xiàn)圖片放大展示效果

    js實現(xiàn)圖片放大展示效果

    這篇文章主要介紹了js實現(xiàn)圖片放大展示效果,點擊圖片可查看放大效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • JavaScript中eval()函數(shù)用法詳解

    JavaScript中eval()函數(shù)用法詳解

    eval() 函數(shù)計算 JavaScript 字符串,并把它作為腳本代碼來執(zhí)行,本文給大家
    2015-12-12

最新評論

开江县| 盐山县| 万源市| 临清市| 义乌市| 柳江县| 岱山县| 沁水县| 柘荣县| 景德镇市| 读书| 北宁市| 彩票| 乐平市| 临澧县| 凤山市| 宝丰县| 安溪县| 榆树市| 白沙| 长沙县| 南木林县| 永靖县| 彭山县| 沂水县| 左贡县| 泗水县| 巴东县| 商城县| 呼图壁县| 江北区| 茶陵县| 哈尔滨市| 宁河县| 昌黎县| 沙坪坝区| 湘乡市| 张北县| 龙南县| 黔江区| 武功县|