前端如何进行系统环境,如CPU/网络环境/内存等监控

2,358 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

背景

近日在浏览文章,看到一篇【动态性能分级策略在客户端的实践】的文章,里面讲述了如何利用收集的设备的信息,如内存、CPU、电量、网速信息进行性能等级判断,业务组件再根据性能等级分析去执行对应的性能策略方案,比如:当你使用oss服务存储图片资源,你可以在整体性能等级优的情况下,去动态修改oss参数,返回更高分辨率的图片,反之降低图片分辨率。

本文整理下,在浏览器环境中如何去监控对应的数据。

系统监控

1. CPU监控

CPU在浏览器中很少被提及,很少有这个概念,往往提及的是js任务执行延迟,在往里细挖就是浏览器的事件循环系统、消息队列、宏任务、微任务、延迟队列等等了。当前面任务发生了阻塞,比如执行了耗时任务,那必然导致后续事件延迟执行了,毕竟js执行是单线程的。Web Api也没有提供获取CPU的方式,那我们怎么获取呢?换句话说,如何计算出单位时间内,js任务执行延迟时间,这也可以反应出当前js执行效率,这也是我们想要的。

看这段代码:

let data = [],t;
let getNow = ()=>new Date().getTime()
const cpuTimer = setInterval(()=>{
   t && data.push(getNow()-t);
   t = getNow();
},500);

理想情况下例子输出的 data值应该是[500,505,508,506,...]在某个范围值内波动,当波动较小时,可以认为当前js任务执行效率高、无存在阻塞的js任务。但是当波动阀值超过,比如:50,我们可以认定存在执行耗能的js任务。

2. 内存监控

Performance提供了对当前页面性能访问的相关信息,比如:Performance Timeline API/ Navigation Timing API/ User Timing API等。在Chrome中添加了一个非标准扩展:Performance.memory,它提供了内存使用的信息。

const {
  // 总分配的堆大小,单位字节
  totalJSHeapSize,
  // 当前使用的js堆,单位字节
  usedJSHeapSize,
  // 上下文可用的最大堆大小,单位字节
  jsHeapSizeLimit} = performance.memory

关于用法,你可以监控浏览器使用内存的阀值,超出则告警:

(()=>{
  // 允许最大50MB
  const MAX_MEMORY_ALLOW = 50 * 1048576; // 50MB
  // 最大使用率90%
  const MAX_MEMORY_PERCENT_ALLOW = 90;
  
  requestAnimationFrame(function monitor(){
    if(performance.memory.usedJSHeapSize > MAX_MEMORY_ALLOW){
      // 高警:使用超过50MB
    }
    if(performance.memory.usedJSHeapSize > (MAX_MEMORY_PERCENT_ALLOW/100)*performance.memory.jsHeapSizeLimit){
      // 告警:使用率超过90%
    }
  })
})()

3. 网络监控

网络监控是为了获取当前时间片段的网速,当网速好,响应更高分辨率的资源图片。Web API也没有提供对应的能力。那获取时间段网络速度,可以通过间断时间,从服务端加载资源文件,计算网速。

function getNetworkSpeed(){
  const startTime = getNow();
  const xhr = new XMLHttpRequest()
  xhr.open('GET', '服务端资源文件,建议给个510M的资源图片')
  xhr.onload = function(){
    // 下载时间
    const duration = (getNow() - startTime)/1000;
    // 转为M
    const size = xhr.getResponseHeader('Content-Length')/1024/1024;
    // 下载速度: * Mb/s
    const speed = (size / duration).toFixed(2)
  }
  xhr.send()
}

4. 电量监控

电量监控主要是为了获取设备低电量状态,在系统电量不足的时候降低一些循环执行任务的频率,从而节约电量。或者在电量减少到某个级别的时候,自动保存页面上的一些数据,以防止用户数据丢失。可以有效降低用户电量焦虑。

Web API 提供了Battery Status API,它提供了2个接口:

  1. BatteryManager:提供有关系统电池电量水平的信息
  2. navigator.getBattery():返回一个Promise对象,resolve 参数是 BatteryManager对象

下面看看用法

function updateBatteryStatus(battery) {  
   // 布尔值,表示电池的充电状态 
   document.querySelector('#charging').textContent = battery.charging ? 'charging' : 'not charging'; 
   // 表示电池的电量等级,从0到1
   document.querySelector('#level').textContent = battery.level;  
   // 表示电量还剩多久时间会消耗完,单位(s)
   document.querySelector('#dischargingTime').textContent = battery.dischargingTime / 60; 
} 

navigator.getBattery().then(function(battery) { 
   // Update the battery status initially when the promise resolves ...   
   updateBatteryStatus(battery); 
   // .. and for any subsequent updates.
   battery.onchargingchange = function () { 
     updateBatteryStatus(battery); 
   }; 
   battery.onlevelchange = function () { 
     updateBatteryStatus(battery); 
   };      
   battery.ondischargingtimechange = function () {         
     updateBatteryStatus(battery); 
   }; 
});

使用此API需要慎重,因为它的兼容性并不好,并且Battery Status API在未来从Web 标准中删除。 兼容性:

battery.jpg

总结

系统环境监控在浏览器中由于存在的兼容性,或者web应用在性能颗粒度上有时候要求并没有这么苛刻,因此此类场景使用上比较少,权当做个了解,扩展下视野。