如何用 JavaScript 判断用户网络状况?教你几招实用方法
做网页开发的时候,我们经常需要知道用户现在的网络好不好。比如看视频的时候,网好就放高清,网差就放流畅版,断网了就提醒用户。今天我就来聊聊怎么用 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 ? '中速' : '高速')
};
}总结
判断网络通不通,先用浏览器的 navigator.onLine 快速判断,再用心跳检测确认后端接口能不能访问。
心跳检测要设置超时时间和失败次数,避免误判。
测网速推荐用图片测速法,简单可靠,兼容性好。
实际项目中,可以结合这两种方法:先判断网络是否通畅,再根据网速决定给用户展示什么内容。
这样就能根据用户的不同网络情况,提供更好的使用体验了。
本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!