一个强大,好用的统计分析系统,能够非常方便的将用户访问数据,站点性能数据,各种统计信息进行汇总展示。这对于有点体量的公司都是非常重要的。
要收集浏览器信息,一般是通过 navigator
对象,从这里面,可以获取到:
navigator.language // 浏览器当前语言
navigator.userAgent // 浏览器信息
navigator.platform // 操作系统平台
navigator.javaEnabled() // 是否支持Java
navigator.maxTouchPoints // 触摸点个数
其次,还会通过 screen
收集屏幕信息:
screen.width // 屏幕宽度
screen.height // 屏幕高度
screen.colorDepth // 屏幕颜色bit
通过 document
获取文档相关信息
document.referrer // 来源站点
document.charset || document.characterSet // 字符编码
要收集性能信息,我们需要通过 performance
对象,其中大致分为:Navigation Timing
, User Timing
以及 Resource Timing
。
首先,通过 var perfData = window.performance.timing;
获取到时间点数据,这些时间数据都是以long类型的UTC时间,数据大致结构如下:
var perfData = {
connectEnd: 1511431220347, // 结束连接
connectStart: 1511431220347, // 开始连接
domComplete: 1511431221532, // DOM渲染完毕
domContentLoadedEventEnd: 1511431220886,
domContentLoadedEventStart: 1511431220884,
domInteractive: 1511431220884,
domLoading: 1511431220680, // 开始DOM渲染
domainLookupEnd: 1511431220347, // 结束DNS解析
domainLookupStart: 1511431220347, // 开始DNS解析
fetchStart: 1511431220347, // 开始Fetch
loadEventEnd: 1511431221565,
loadEventStart: 1511431221532,
navigationStart: 1511431220272, // 开始导航
redirectEnd: 0, // 结束跳转
redirectStart: 0, // 开始跳转
requestStart: 1511431220353, // 开始请求
responseEnd: 1511431220680, // 结束响应
responseStart: 1511431220678, // 开始响应
secureConnectionStart: 0, // 开始安全连接
unloadEventEnd: 0,
unloadEventStart: 0
}
以此,我们可以得出如下时间数据:
var dnsLookupTime = perfData.domainLookupEnd - perfData.domainLookupStart; // DNS解析耗时
var tcpConnectTime = perfData.connectEnd - perfData.connectEnd; // TCP连接耗时
var pageLoadTime = perfData.loadEventEnd - perfData.navigationStart; // 页面加载时间,对应 Network 的 Load
var sendRequestTime = pertData.responseStart - perfData.requestStart; // 发送请求耗时
var serverResponseTime = pertData.responseEnd - perfData.responseStart; // 服务端响应耗时
var renderTime = perfData.domComplete - perfData.domLoading; // 页面渲染所用的时间
var domContentLoadedTime = perfData.domContentLoadedEventEnd - perfData.navigationStart;// 页面内容加载时间,对应 Network 的 DOMContentLoaded
var resolveDomTreeTime = perfData.domComplete - perfData.domInteractive; // 解析DOM树耗时
var whiteScreenTime = perfData.domLoading - perfData.navigationStart; // 白屏时间
对于异常来说,我们一般会提供自动异常收集,也需要允许主动上报异常。
我们可以监控 window.error
,然后获取到错误信息,进行上报。
window.addEventListener('error', function (evt) {
console.log(evt);
}, false);
对于主动上报的话,我们仅仅需要提供一个方法,来触发一次上报即可。
trackException(evt) {
const self = this;
const data = getExceptionData(evt);
data.tid = self._tid;
data.t = 'exception';
report(self._url, data);
}
在我们的上报客户端JS中,我们应该尽量少的去使用Ajax请求这些相对复杂的东西,而且也要考虑兼容性问题以及上报成功率。这个时候,我们可以考虑如下做法:
通过 navigator.sendBeacon
来进行上报,这是现在浏览器的新特新,能保持一定上报。所以,我们会优先使用它来进行上报。
那如果该特性并不可用的时候呢?发ajax请求么?不。我们可以采用构造图片请求的做法来实现:
var img = new Image();
img.src = reportUrl;
就这么简单么?也不是这么简单,我们还需要考虑这个请求是否可能发不出去(在遇到内存回收时,该变量由于没有被引用,会被回收掉,所以可能发不出去),为了提高成功率,我们应该按照如下做法实现:
const rndKey = `report_img_${makeRndString()}`;
const img = window.WebMoniter[rndKey] = new Image();
img.onload = img.onerror = function () {
window.WebMoniter[rndKey] = null; // 手动清理
}
img.src = reportUrl;
通过构造一个随机数key,把引用放到window上,在发送完成(包括成功和失败)后,进行清理动作。
注意:该做法会有url长度限制,要尽量保证URL不至于太长。
待续...