这里记录工作中遇到的技术点,以及自己对生活的一些思考,周三或周五发布。
封面图
思路
最近一直在忙着业务上的事情,所以对前端监控的实现方案思考花的时间少了一些,昨天大概又思考了一。如果我们抛开页面时长,深度,PV,UV等相关的需求,单独把监控请求拿出来的话,我可能会按照上面那个图去实现一个简单的功能。
整体上可能会分为四个小模块儿,rester,watcher,timer,reporter,图上应该还少了一个队列的模块,队列模块儿用来缓存每次请求我们想要监听的数据。
reseter 用来重置XHR对象。对XHR对象进行改造,使它具备监听请求的功能。
watcher 用来对每次请求的数据进行监听,并修改数据成我们想要的格式。
repoter 用来实现上报功能。具体实现可以使用原生的xhr对象,也可以使用sendBeacon。
timer 用来开启定时任务或者控制任务队列,使我们可以定时上报数据,或者每10条,20条,或者30条数据上报一次。
从这个功能的划分上,让我想起来了vuex的代码。vuex中定义了两个变量来缓存actions和mutations,当每次提交action或者mutation的时候,会从这两个缓存变量中遍历取到对应的action或mutation进行执行。
从实现方式的角度讲,我们可以借鉴vuex的实现方式。
计算请求时长
计算请求时长,需要我们了解下面这个API。
Resource Timing API
Resource Timing API可以获取和分析应用资源加载的详细网络计时数据,应用程序可以
使用时间度量标准来确定加载特定资源所需要的时间,比如 XMLHttpRequest, <SVG>, 图片,或者脚本。
同时可以为网络事件 (如重定向的开始和结束事件,DNS 查找的开始和结束事件,请求开始,响应开始和结束时间等) 生成有高精度时间戳 ( high-resolution timestamps ) 的资源加载时间线,并提供了资源大小和资源类型。
需要注意的是:PerformanceResourceTiming
接口只统计performance entries 中 entryType 为"resource
"类型的 PerformanceEntry
performance.getEntriesByType()
getEntriesByType()
方法返回给定类型的 PerformanceEntry 列表
PerformanceEntry
PerformanceEntry
connectEnd: 76.80000001192093
connectStart: 33.5
decodedBodySize: 130302
domComplete: 1864.3999999761581
domContentLoadedEventEnd: 1013.1999999880791
domContentLoadedEventStart: 875.5999999642372
domInteractive: 873.3000000119209
domainLookupEnd: 33.5
domainLookupStart: 4.899999976158142
duration: 1875.0999999642372
encodedBodySize: 29330
entryType: "navigation"
fetchStart: 4.399999976158142
initiatorType: "navigation"
loadEventEnd: 1875.0999999642372
loadEventStart: 1864.5
name: "https://zhuanlan.zhihu.com/p/161573162"
nextHopProtocol: "h2"
redirectCount: 0
redirectEnd: 0
redirectStart: 0
requestStart: 77
responseEnd: 265.30000001192093
responseStart: 247.0999999642372
secureConnectionStart: 53.80000001192093
serverTiming: []
startTime: 0
transferSize: 29630
type: "navigate"
unloadEventEnd: 0
unloadEventStart: 0
workerStart: 0
我们可以看到诸如domainLookupStart
,domainLookupEnd
,或者redirectStart
,redirectEnd
以及requestStart
,responseStart
,responseEnd
等属性。
我们的请求时长可以根据这些属性进行计算,同时我们也可以在我们想要手机的消息中添加一些其他的内容,比如地址解析时间,重定向时间,等等。
具体计算,我们大致的代码可能如下:
// 示例代码,没啥用
calcTiming(url: string): {
redirectDuration?: number;
dnsDuration?: number;
connectDuration?: number;
requestDuration?: number;
responseDuration?: number;
rawPerformance?: PerformanceResourceTiming;
} {
const fullUrl = (new UrlParser(url)).href;
let p: PerformanceEntry | undefined;
let entries = window.performance.getEntriesByName(fullUrl);
p = entries[0]
const {redirectStart, redirectEnd, domainLookupStart, domainLookupEnd, connectStart, connectEnd, requestStart, responseStart, responseEnd } = p as PerformanceResourceTiming;
return {
['redirectDuration']: redirectEnd - redirectStart,
['dnsDuration']: domainLookupEnd - domainLookupStart,
['connectDuration']: connectEnd - connectStart,
['requestDuration']: responseStart - requestStart,
['responseDuration']: responseEnd - responseStart,
rawPerformance: (p as PerformanceResourceTiming).toJSON()
};
} else {
return
主要的就是这个计算:
'redirectDuration']: redirectEnd - redirectStart,
['dnsDuration']: domainLookupEnd - domainLookupStart,
['connectDuration']: connectEnd - connectStart,
['requestDuration']: responseStart - requestStart,
['responseDuration']: responseEnd - responseStart,
这个计算过程,我们可以在监听到请求响应数据时进行,然后把计算好的数据缓存到全局的队列中,这样,定时器或者任务队列在上报数据时,我们就可以得到相对精度较高的数据。
最后
这篇仅仅对XMLHttpRequest
监控方案的实现思路以及请求时长的计算方法做一个简单的分析。
等手头的事情忙个差不多之后,会做一个简单的实现,谢谢大家。
未完待续...
如果喜欢。
请点赞,最好也加个"关注",或者分享到朋友圈。