如何用 JavaScript 判断用户网络状况?教你几招实用方法

更新日期: 2026-03-24 阅读: 15 标签: 网络

做网页开发的时候,我们经常需要知道用户现在的网络好不好。比如看视频的时候,网好就放高清,网差就放流畅版,断网了就提醒用户。今天我就来聊聊怎么用 JavaScript 判断用户网络情况,包括是在线还是离线,网速快不快。


一、怎么判断用户在线还是离线?

浏览器自带了一个简单的判断方法:navigator.onLine。这个属性会返回 true 或 false,告诉你当前浏览器认为网络通不通。

// 看看当前网络状态
if (navigator.onLine) {
  console.log('网络在线');
} else {
  console.log('网络已断开');
}

// 监听网络变化
window.addEventListener('online', () => {
  console.log('网络连上了');
});

window.addEventListener('offline', () => {
  console.log('网络断了');
});

但这个方法有个问题:它只能判断浏览器有没有连接到网络,判断不了这个网络能不能真的访问你的服务器。举个例子,你连着商场的WiFi,但没登录认证,浏览器显示在线,实际上没法上网。这时候就需要更靠谱的方法。


二、用心跳检测判断网络是否真的可用

心跳检测就像是你每隔一段时间给你的服务器发个消息:“在吗?”如果服务器回复了,说明网络是好的。要是连着几次都没回复,那就说明网络可能真的出问题了。

下面是一个简单实用的心跳检测代码

class NetworkCheck {
  constructor(options = {}) {
    this.options = {
      checkUrl: '/api/ping',      // 检测的接口地址
      interval: 30000,             // 每30秒检测一次
      timeout: 5000,               // 5秒超时
      onStatusChange: null,        // 状态改变时的回调
      ...options
    };
    
    this.isOnline = navigator.onLine;
    this.checking = false;
    this.timer = null;
    this.failCount = 0;
    this.maxFailCount = 2;          // 连续失败2次就判定为断网
    
    this.init();
  }

  init() {
    // 监听浏览器的网络事件
    window.addEventListener('online', () => this.onBrowserOnline());
    window.addEventListener('offline', () => this.onBrowserOffline());
    
    this.startCheck();
  }

  startCheck() {
    this.stopCheck();
    this.timer = setInterval(() => this.check(), this.options.interval);
    this.check();  // 立即检测一次
  }

  stopCheck() {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
  }

  async check() {
    if (this.checking) return;
    
    this.checking = true;
    
    try {
      // 发起一个轻量级请求
      const response = await fetch(this.options.checkUrl, {
        method: 'HEAD',
        cache: 'no-cache',
        headers: {
          'X-Network-Check': 'ping'
        }
      });
      
      // 请求成功,网络正常
      this.onSuccess();
      
    } catch (error) {
      // 请求失败
      this.onFail();
    } finally {
      this.checking = false;
    }
  }

  onSuccess() {
    this.failCount = 0;
    
    if (!this.isOnline) {
      this.setStatus(true);
    }
  }

  onFail() {
    this.failCount++;
    
    // 连续失败达到设定次数,判定为断网
    if (this.failCount >= this.maxFailCount && this.isOnline) {
      this.setStatus(false);
    }
  }

  onBrowserOnline() {
    // 浏览器说在线了,再验证一下
    this.check();
  }

  onBrowserOffline() {
    this.setStatus(false);
  }

  setStatus(status) {
    if (this.isOnline !== status) {
      this.isOnline = status;
      
      if (this.options.onStatusChange) {
        this.options.onStatusChange(status);
      }
      
      // 也可以发个自定义事件,方便其他地方监听
      window.dispatchEvent(new CustomEvent('netstatus', {
        detail: { online: status }
      }));
    }
  }

  async checkNow() {
    return this.check();
  }

  destroy() {
    this.stopCheck();
    window.removeEventListener('online', this.onBrowserOnline);
    window.removeEventListener('offline', this.onBrowserOffline);
  }
}

// 使用方法
const checker = new NetworkCheck({
  checkUrl: 'https://你的域名/api/ping',
  interval: 15000,
  onStatusChange: (online) => {
    if (online) {
      console.log('网络恢复了,可以同步数据');
      // 这里可以触发数据同步等操作
    } else {
      console.log('网络断了,进入离线模式');
      // 这里可以保存数据到本地
    }
  }
});

后端只需要提供一个简单的接口,返回200状态码就行:

// Node.js + Express 示例
app.head('/api/ping', (req, res) => {
  res.status(200).end();
});


三、怎么测网速?

知道了网络通不通还不够,有时候我们还想知道网速快不快,这样才能决定给用户展示什么内容。

1. 浏览器自带的网速信息(不推荐)

浏览器有个 navigator.connection 接口,可以拿到一些网络信息:

console.log('网络类型:', navigator.connection.effectiveType); // 4g, 3g, 2g
console.log('下行速度:', navigator.connection.downlink, 'Mbps');

但这个接口有几个问题:一是兼容性不好,很多浏览器不支持;二是数据不太准,跟实际测速结果有差距。所以实际项目中很少用它。

2. 图片测速法(推荐)

这个方法很简单:让浏览器下载一张图片,记录下载时间,用图片大小除以时间就能算出大概的网速。

class SpeedTest {
  constructor() {
    this.speed = 0;
  }

  // 测速
  async test() {
    // 准备一张图片,大小大概100KB左右
    const imgUrl = 'https://你的域名/speed-test.jpg?t=' + Date.now();
    const startTime = Date.now();
    
    try {
      const response = await fetch(imgUrl);
      const blob = await response.blob();
      const endTime = Date.now();
      
      // 图片大小(字节)
      const size = blob.size;
      // 下载时间(秒)
      const duration = (endTime - startTime) / 1000;
      // 计算速度(KB/秒)
      const speedKBps = size / duration / 1024;
      // 换算成Mbps(1Mbps = 128KB/秒)
      const speedMbps = speedKBps / 128;
      
      this.speed = speedMbps;
      
      return {
        speedMbps: speedMbps.toFixed(2),
        level: this.getLevel(speedMbps)
      };
    } catch (error) {
      console.log('测速失败', error);
      return null;
    }
  }
  
  // 根据网速判断网络等级
  getLevel(speedMbps) {
    if (speedMbps < 0.5) return '慢速';
    if (speedMbps < 2) return '中速';
    return '高速';
  }
}

// 使用
const tester = new SpeedTest();
const result = await tester.test();
if (result) {
  console.log(`网速:${result.speedMbps}Mbps,属于${result.level}网络`);
}

为了提高准确率,可以测两次取平均值:

async function getAverageSpeed() {
  const tester = new SpeedTest();
  const speeds = [];
  
  // 测两次
  for (let i = 0; i < 2; i++) {
    const result = await tester.test();
    if (result) {
      speeds.push(parseFloat(result.speedMbps));
    }
    // 间隔一下再测第二次
    await new Promise(resolve => setTimeout(resolve, 1000));
  }
  
  if (speeds.length === 0) return null;
  
  const avg = speeds.reduce((a, b) => a + b, 0) / speeds.length;
  return {
    speedMbps: avg.toFixed(2),
    level: avg < 0.5 ? '慢速' : (avg < 2 ? '中速' : '高速')
  };
}


总结

  1. 判断网络通不通,先用浏览器的 navigator.onLine 快速判断,再用心跳检测确认后端接口能不能访问。

  2. 心跳检测要设置超时时间和失败次数,避免误判。

  3. 测网速推荐用图片测速法,简单可靠,兼容性好。

  4. 实际项目中,可以结合这两种方法:先判断网络是否通畅,再根据网速决定给用户展示什么内容。

这样就能根据用户的不同网络情况,提供更好的使用体验了。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13485

相关推荐

kubernetes之Flannel网络插件部署

Kubernetes系统上Pod网络的实现依赖于第三方插件,而Flannel是由CoreOS主推的目前比较主流的容器网络解决方案,CNI插件有两种功能:网络配置和网络策略,由于flannel比较简单,并不支持网络策略

Deepfake_深度神经网络换脸

Deepfake从技术的角度而言,这是深度图像生成模型的一次非常成功的应用,这两年虽然涌现出了很多图像生成模型方面的论文,但大都是能算是Demo,没有多少的实用价值,除非在特定领域(比如医学上)

怎么用nodejs检测网络状态?

nodejs可以使用检测因特网状态的库internet-available、is-online来检查网络状态,其原理是检测dns连接状态。这两个库提供了超时检测。internet-available这个库检测因特网连接状态原理,是检测dns连接状态。

Angular网络请求

在Angular网络请求是一个最常见的应用之一,下列我将以 ng-alain 项目为基础描述 Angular 网络请求。注:示例中代码都以简化的形式出现。

全面分析前端的网络请求方式

大多数情况下,在前端发起一个网络请求我们只需关注下面几点:传入基本参数(url,请求方式),请求参数、请求参数类型,设置请求获取响应的方式

2019最新网络赚钱方法有哪些?推荐几种靠谱赚钱方式!

2019年已经是互联网发展的成熟期了,随着网络的不断发展,以及手机应用的普及,几乎人人都已经会使用网络工具。但是又有多少人知道网络赚钱这个小众的赚钱方式呢?

由Web Beacon-网络臭虫引发的思考

为何在百度搜索之后,一些网站总能够推荐我刚刚搜索过的东西?百度会记录你的搜索信息,同时会在你本地保存一个标识本地的cookie,而当你打开第三方网站时,第三方网站嵌入了百度广告的JS代码

JS 测试网络速度与网络延迟

通过js加载一张1x1的极小图片,测试出图片加载的所用的时长。如果换一个几百KB的图片,则可心用来计算下载网速 ,第一次加载图像时,它将比后续加载花费更长的时间,即使我们确保图像没有被缓存。

浅谈对soket的理解

网络上的两个程序通过一个双向的通信链实现数据的交换,这个链接的一端就成为Socket,它是进程通信的一种,即调用这个网络库的api函数实现分布在不同主机相关进程之间的数据交换

计算机网络常见问题

为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!