Network Information API

深入理解 Network Information API:navigator.connection、effectiveType 和 saveData、根据网络条件调整内容质量、以及 Navigator API。

Network Information API

一、为什么需要 Network Information API

1.1 自适应内容的必要性

用户的网络条件差异巨大:有人在 5G 下快速冲浪,有人在 2G 下艰难加载。同样一张图片、一个视频,在不同网络下应该有不同的质量。

Network Information API 允许 Web 应用了解用户的网络环境,从而做出合适的决策。

1.2 API 概述

if ('connection' in navigator) {
  const connection = navigator.connection;
  console.log('网络类型:', connection.effectiveType);
  console.log('估算带宽:', connection.downlink, 'Mbps');
  console.log('节省数据模式:', connection.saveData);
}

二、Navigator Connection API

2.1 基本属性

const connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;

// 网络类型
connection.effectiveType; // 'slow-2g' | '2g' | '3g' | '4g'

// 估算带宽(Mbps)
connection.downlink;

// 往返延迟(ms)
connection.rtt;

// 是否启用节省数据模式
connection.saveData;

// 是否在线
navigator.onLine;

// CPU 核心数
navigator.hardwareConcurrency;

// 设备内存(GB)
navigator.deviceMemory;

2.2 监听网络变化

connection.addEventListener('change', () => {
  console.log('网络变化:', connection.effectiveType);
  console.log('带宽变化:', connection.downlink);

  // 根据新网络条件调整内容
  adjustContentQuality();
});

三、effectiveType 和 saveData

3.1 effectiveType

effectiveType 表示当前网络的有效类型:

// 'slow-2g' - 非常慢的网络,如 2G
// '2g' - 慢 2G 网络
// '3g' - 3G 网络
// '4g' - 4G 或更快的网络

function getContentStrategy() {
  const type = navigator.connection?.effectiveType;

  switch (type) {
    case 'slow-2g':
    case '2g':
      return {
        imageQuality: 'low',
        preloadVideo: false,
        autoplayVideo: false,
        imageFormat: 'progressive-jpeg'
      };
    case '3g':
      return {
        imageQuality: 'medium',
        preloadVideo: false,
        autoplayVideo: false,
        imageFormat: 'webp'
      };
    case '4g':
      return {
        imageQuality: 'high',
        preloadVideo: true,
        autoplayVideo: true,
        imageFormat: 'avif'
      };
    default:
      return {
        imageQuality: 'medium',
        preloadVideo: true,
        autoplayVideo: false,
        imageFormat: 'webp'
      };
  }
}

3.2 saveData

saveData 表示用户启用了节省数据模式:

function shouldLoadHighQuality() {
  // 用户明确要求节省数据
  if (navigator.connection?.saveData) {
    return false;
  }

  // 或者网络很慢
  const type = navigator.connection?.effectiveType;
  if (type === 'slow-2g' || type === '2g') {
    return false;
  }

  return true;
}

四、自适应内容策略

4.1 图片质量自适应

class AdaptiveImageLoader {
  constructor() {
    this.connection = navigator.connection;
    this.quality = this.determineQuality();
  }

  determineQuality() {
    if (this.connection?.saveData) return 'low';
    if (this.connection?.effectiveType === '4g') return 'high';
    if (this.connection?.effectiveType === '3g') return 'medium';
    return 'low';
  }

  getImageUrl(baseUrl) {
    const quality = this.quality;

    if (quality === 'low') {
      return baseUrl.replace('/upload/', '/upload/w_300,f_auto,q_auto:low/');
    } else if (quality === 'medium') {
      return baseUrl.replace('/upload/', '/upload/w_800,f_auto,q_auto:medium/');
    } else {
      return baseUrl.replace('/upload/', '/upload/w_1200,f_auto,q_auto:best/');
    }
  }

  loadImage(imgElement, url) {
    imgElement.src = this.getImageUrl(url);
  }
}

4.2 视频码率自适应

class AdaptiveVideoPlayer {
  constructor(videoElement) {
    this.video = videoElement;
    this.connection = navigator.connection;
  }

  selectQuality() {
    const type = this.connection?.effectiveType;
    const downlink = this.connection?.downlink || 5;

    if (type === 'slow-2g' || type === '2g') {
      return { url: this.lowQualityUrl, bitrate: 256 };
    } else if (type === '3g' || downlink < 5) {
      return { url: this.mediumQualityUrl, bitrate: 512 };
    } else {
      return { url: this.highQualityUrl, bitrate: 2048 };
    }
  }

  loadVideo() {
    const { url } = this.selectQuality();
    this.video.src = url;
  }
}

4.3 预加载策略

class SmartPreloader {
  constructor() {
    this.connection = navigator.connection;
  }

  shouldPreload(resourceType) {
    // 节省数据模式,不预加载
    if (this.connection?.saveData) {
      return false;
    }

    const type = this.connection?.effectiveType;

    // 预加载决策
    if (type === '4g') {
      return true; // 预加载所有
    } else if (type === '3g') {
      return resourceType !== 'video'; // 不预加载视频
    } else {
      return resourceType === 'critical'; // 只预加载关键资源
    }
  }
}

五、其他 Navigator API

5.1 navigator.onLine

window.addEventListener('online', () => {
  console.log('网络已连接');
  syncData();
});

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

5.2 navigator.hardwareConcurrency

// 获取 CPU 核心数
const cores = navigator.hardwareConcurrency;
console.log(`CPU 核心数: ${cores}`);

// 根据核心数决定并行度
const workers = Math.min(cores, 4);

5.3 navigator.deviceMemory

// 获取设备内存(GB)
const memory = navigator.deviceMemory;
console.log(`设备内存: ${memory}GB`);

// 根据内存决定缓存策略
if (memory < 4) {
  // 低内存设备使用更小的缓存
  cacheSize = 50 * 1024 * 1024; // 50MB
} else {
  cacheSize = 200 * 1024 * 1024; // 200MB
}

六、注意事项

6.1 API 支持情况

Network Information API 不是所有浏览器都支持:

if ('connection' in navigator) {
  // 支持
} else {
  // 不支持,使用默认值
}

6.2 隐私考虑

这些 API 可能被用于指纹识别。浏览器可能会限制返回值的精度:

// 带宽可能不是精确值,而是估算值
const downlink = navigator.connection?.downlink; // 可能是 5 而不是精确值

延展阅读