sdk监控系统开发

参考部分文献

1.首次给系统建立链接给客户端分配服务id,主要用于建立客户端标识,减少没必要的重复数据。

2. 根据Performance API获取前端性能数据,获取首次页面加载的性能数据

let times = {};
  let t = window.performance.timing;
  
  //重定向时间
  times.redirectTime = t.redirectEnd - t.redirectStart;
  
  //dns查询耗时
  times.dnsTime = t.domainLookupEnd - t.domainLookupStart;
  
  //TTFB 读取页面第一个字节的时间
  times.ttfbTime = t.responseStart - t.navigationStart;
  
  //DNS 缓存时间
  times.appcacheTime = t.domainLookupStart - t.fetchStart;
  
  //卸载页面的时间
  times.unloadTime = t.unloadEventEnd - t.unloadEventStart;
  
  //tcp连接耗时
  times.tcpTime = t.connectEnd - t.connectStart;
  
  //request请求耗时
  times.reqTime = t.responseEnd - t.responseStart;
  
  //解析dom树耗时
  times.analysisTime = t.domComplete - t.domInteractive;
  
  //白屏时间
  times.blankTime = t.domLoading - t.fetchStart;
  
  //domReadyTime
  times.domReadyTime = t.domContentLoadedEventEnd - t.fetchStart;

2.异步获取需要分析的数据

let  entryTimesList = [];
  let entryList = window.performance.getEntries();
  entryList.forEach((item,index)=>{
  
     let templeObj = {};
     
     let usefulType = ['script','css','fetch','xmlhttprequest','link','img'];
     if(usefulType.indexOf(item.initiatorType)>-1){
       templeObj.name = item.name;
       
       templeObj.nextHopProtocol = item.nextHopProtocol;
      
       //dns查询耗时
       templeObj.dnsTime = item.domainLookupEnd - item.domainLookupStart;

       //tcp链接耗时
       templeObj.tcpTime = item.connectEnd - item.connectStart;
       
       //请求时间
       templeObj.reqTime = item.responseEnd - item.responseStart - startTime;

       //重定向时间
       templeObj.redirectTime = item.redirectEnd - item.redirectStart;

       entryTimesList.push(templeObj);
     }
  });

3.错误监听

3-1:window js语法报错

window.onerror = function (e) {
//...deal with something
}

3-2:promise catch错误捕获未处理

window.addEventListener('unhandledrejection', (e) => {
    console.log(e, 'promise事件回调监控')
})

3-3:vue的错误捕获

//vue错误捕获
let vuePlugin = function (error, _Vue) {
    if (!_Vue || !_Vue.config) {
        return;
    }
    let _oldOnError = _Vue.config.errorHandler;
    _Vue.config.errorHandler = function (errMsg, vm, info) {
        error(errMsg)
        if (typeof console != 'undefined' && typeof console.error == 'function') {
            console.error(errMsg)
        }
        if (typeof _oldOnError == 'function') {
            _oldOnError.call(this, errMsg, vm, info)
        }
    }
}
try {
    vuePlugin(window.onerror, Vue)
} catch (error) {

}

3-4获取跨域的JavaScript错误,对监听器进行拦截重写,默认情况下a域名下的js是抓不到b域名下js的报错信息

//跨域javasctipt错误
const originAddEventListener = EventTarget.prototype.addEventListener,errObj={};
EventTarget.prototype.addEventListener = (type, listener, options) => {
    const wrappedListener = (...args) => {
        errObj.dedetail = {//获取最后事件的dom节点信息
            outerHTML:args[0].srcElement.outerHTML,
            "className":args[0].srcElement.className,
            "id":args[0].srcElement.id,
            "tagName":args[0].srcElement.nodeName
        }
        errObj.type = type
        try {
            if(args[0].srcElement.nodeName!=undefined){
                return listener.apply(this, args)
            }
        } catch (error) {
            throw error
        }
    }
    return originAddEventListener.call(this, type, wrappedListener, options)
}

4.何时上传数据

  • 页面加载和重新刷新
  • 页面切换路由
  • 页面所在的tab标签重新变得可见 
  • 页面报错
  • 网络请求

对上述的前3种场景,特别是切换路由的情况,如果切换路由是通过改变hash值来实现的,那么只需要监听hashchange事件,如果是通过html5的history api来改变url的,那么需要重新定义pushstate和replacestate事件。
直接给出history实现路由场景下监听url改变的方案:

var _wr = function(type) {
   var orig = history[type];
   return function() {
       var rv = orig.apply(this, arguments);
      var e = new Event(type);
       e.arguments = arguments;
       window.dispatchEvent(e);
       return rv;
   };
};
 history.pushState = _wr('pushState');
 history.replaceState = _wr('replaceState');
然后我们就可以根据上述场景,分别监听相应的事件,从而实现前端性能数据的上报:
addEvent(window,'load',function(e){
    ...deal with something
});
//监控history基础上实现的单页路由中url的变化
addEvent(window,'replaceState', function(e) {
    ...deal with something
});
addEvent(window,'pushState', function(e) {
    ...deal with something
});
//通过hash切换来实现路由的场景
addEvent(window,'hashchange',function(e){
   ...deal with something
});
addEvent('document','visibilitychang',function(e){
   ...deal with something
})

5.使用sendBeacon方法上传数据

该方法发送数据没有返回值,不需要握手协议(在页面销毁期,可以异步的发送数据,因此不会造成类似同步ajax请求那样的阻塞问题,也不会影响下一个页面的渲染),下边对该方法做了简单的封装。

p:navigator.sendBeacon的兼容性如下,并不是很好,因此我们可以判断请求navigator.sendBeacon不支持时用XMLHttpRequest去请求。

const reportData = (url, data) => {
    const formData = new FormData();
    Object.keys(data).forEach((key) => {
        let value = data[key];
        if (typeof value !== 'string') {
            // formData只能append string 或 Blob
            value = JSON.stringify(value);
        }
        formData.append(key, value);
    });
    navigator.sendBeacon(url, formData);
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

槿畔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值