前端性能和错误监控

本地缓存在localStorage中的监控对象

export default function monitorInit(timeout = 7 * 24 * 60 * 60) {
  let whiteScreen = new Date() - performance.timing.navigationStart;
  const monitor = {    // 数据上传地址
    // url: '',
    // 性能信息    performance: {},    // 资源信息    resources: {},    // 错误信息    errors: {},    // 用户信息    client: {      // 屏幕宽度      screen: screen.width,      // 屏幕高度      height: screen.height,      // 浏览器平台      platform: navigator.platform,      // 浏览器的用户代理信息      userAgent: navigator.userAgent,      // 浏览器用户界面的语言      language: navigator.language
    },
    cacheTime: new Date().getTime(),
    timeout: timeout    // 手动添加错误
    // addError(error) {
    //   const obj = {};
    //   const { type, msg, url, row, col } = error;
    //   if (type) obj.type = type;
    //   if (msg) obj.msg = msg;
    //   if (url) obj.url = url;
    //   if (row) obj.row = row;
    //   if (col) obj.col = col;
    //   obj.time = new Date().getTime();
    //   monitor.errors.push(obj);
    // },
    // 重置 monitor 对象
    // reset() {
    //   window.performance && window.performance.clearResourceTimings();
    //   monitor.performance = getPerformance();
    //   monitor.resources = getResources();
    //   monitor.errors = {};
    // },
    // 清空 error 信息
    // clearError() {
    //   monitor.errors = {};
    // },
    // 上传监控数据
    // upload() {
    // 自定义上传
    // axios.post({
    //     url: monitor.url,
    //     data: {
    //         performance,
    //         resources,
    //         errors,
    //         user,
    //     }
    // })
    // },
    // 设置数据上传地址
    // setURL(url) {
    //   monitor.url = url;
    // }  };

  const getMonitor = () => {
    isOverTime();    return JSON.parse(localStorage.getItem('monitor'));
  };

  const isOverTime = () => {
    const data = JSON.parse(localStorage.getItem('monitor'));    // 没有数据 一定超时
    if (!data) {      return true;
    }    // 获取系统当前时间戳
    const currentTime = new Date().getTime();    // 获取当前时间与存储时间的过去的秒数
    const overTime = (currentTime - data.cacheTime) / 1000;    // console.log(overTime);
    // 如果过去的秒数大于当前的超时时间,也返回null让其去服务端取数据
    if (overTime > data.timeout) {
      localStorage.removeItem('monitor');      return true;
    }    return false;
  };  // 获取性能信息
  const getPerformance = () => {    if (!window.performance) return;
    const timing = window.performance.timing;
    const performance = {      // 重定向耗时
      redirect: timing.redirectEnd - timing.redirectStart,      // 白屏时间      whiteScreen: whiteScreen,      // DOM 渲染耗时
      dom: timing.domComplete - timing.domLoading,      // 页面加载耗时
      load: timing.loadEventEnd - timing.navigationStart,      // 页面卸载耗时
      unload: timing.unloadEventEnd - timing.unloadEventStart,      // 请求耗时
      request: timing.responseEnd - timing.requestStart,      // 获取性能信息时当前时间
      time: new Date().getTime()
    };    return performance;
  };  // 获取资源信息
  const getResources = () => {    if (!window.performance) return;
    const data = window.performance.getEntriesByType('resource');
    const resource = {
      xmlhttprequest: [],
      css: [],
      other: [],
      script: [],
      img: [],
      link: [],
      fetch: [],      // 获取资源信息时当前时间
      time: new Date().getTime()
    };

    data.forEach(item => {
      const arry = resource[item.initiatorType];
      arry &&
        arry.push({          // 资源的名称          name: item.name,          // 资源加载耗时
          duration: item.duration.toFixed(2),          // 资源大小          size: item.transferSize,          // 资源所用协议          protocol: item.nextHopProtocol
        });
    });    return resource;
  };

  window.onload = () => {    // 在浏览器空闲时间获取性能及资源信息 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback
    let monitorObj = getMonitor() ? getMonitor() : monitor;    if (window.requestIdleCallback) {
      window.requestIdleCallback(() => {
        monitorObj.performance = getPerformance();        // console.log('页面性能信息');
        // console.log(monitor.performance);
        monitorObj.resources = getResources();        // console.log('页面资源信息');
        // console.log(monitor.resources);
        localStorage.setItem('monitor', JSON.stringify(monitorObj));
      });
    } else {
      setTimeout(() => {
        monitor.performance = getPerformance();        // console.log('页面性能信息');
        // console.log(monitor.performance);
        monitor.resources = getResources();        // console.log('页面资源信息');
        // console.log(monitor.resources);
        localStorage.setItem('monitor', JSON.stringify(monitor));
      }, 0);
    }
  };  // 捕获资源加载失败错误 js css img...  addEventListener(    'error',
    e => {
      const target = e.target;      if (target !== window) {
        let monitorObj = getMonitor() ? getMonitor() : monitor;
        let url = target.src || target.href;        if (!monitorObj.errors[url]) {
          monitorObj.errors[url] = {
            type: target.localName,
            url: url,
            msg: (target.src || target.href) + ' is load error',            // 错误发生的时间
            time: new Date().getTime()
          };
          localStorage.setItem('monitor', JSON.stringify(monitorObj));          // console.log('所有的错误信息');
          // console.log(monitor.errors);        }
      }
    },    true
  );  // 监听 js 错误
  window.onerror = function(msg, url, row, col, error) {
    let monitorObj = getMonitor() ? getMonitor() : monitor;
    let key = `${url}:${row}`;    if (!monitorObj.errors[key]) {
      monitorObj.errors[key] = {
        type: 'javascript', // 错误类型
        row: row, // 发生错误时的代码行数
        col: col, // 发生错误时的代码列数
        msg: error && error.stack ? error.stack : msg, // 错误信息
        url: url, // 错误文件
        time: new Date().getTime() // 错误发生的时间
        // console.log('所有的错误信息');
        // console.log(monitor.errors);      };
      localStorage.setItem('monitor', JSON.stringify(monitorObj));
    }
  };  // 监听 promise 错误 缺点是获取不到行数数据
  addEventListener('unhandledrejection', e => {
    let monitorObj = getMonitor() ? getMonitor() : monitor;
    let msg = (e.reason && e.reason.msg) || e.reason || '';    if (!monitorObj.errors[msg]) {
      monitorObj.errors[msg] = {
        type: 'promise',
        msg: msg,        // 错误发生的时间
        time: new Date().getTime()
      };      // console.log('所有的错误信息');
      // console.log(monitor.errors);
      localStorage.setItem('monitor', JSON.stringify(monitorObj));
    }
  });  return monitor;
}

 


上一篇:安卓逆向入门期之在环境配置环节踩的坑


下一篇:Improve your spoken english