1.0.0 • Published 5 years ago

performance-monitor v1.0.0

Weekly downloads
1
License
MIT
Repository
-
Last release
5 years ago

使用

npm安装

//安装依赖
npm install --save-dev wy-performance-monitor

//使用
import Monitor from 'wy-performance-monitor'
let m = new WebMonitor({
	 //项目名称(必填)
     appId: 'your app',
     // 上报地址(必填)
	 url:"your report address",
     // 是否上报页面性能数据
     isPage: true,
     // 是否上报ajax性能数据
     isAjax: true,
     // 是否上报页面资源数据
     isResource: true,
     // 监控警告线,超过即上报
     limitDutration: 3000,
     // 网络状况
     network: null,
     //延迟请求resource时间(等待请求完成多久后开始监控)
     resourceDelay: 6000,
     //过滤掉的资源或者请求地址
	 filter:[
		"baidu.com",  //一级域名
		"www.baidu.com",//二级域名
		"http://www.baidu.com/read" //完整链接
	 ] 
})
//增加上传信息
m.add({
	author:'superman'
})

页面插入代码

    let s = document.createElement("script")
    s.src = "https://res.winbaoxian.com/autoUpload/activity/index_7854ee73401bdf2.js"
    document.body.appendChild(s)
    s.onload = function () {
        let m = new Monitor({
            //项目名称(必填)
            appId: null,
            // 上报地址(必填)
            url:"your report address",
            // 是否上报页面性能数据
            isPage: true,
            // 是否上报ajax性能数据
            isAjax: true,
            // 是否上报页面资源数据
            isResource: true,
            // 监控警告线,超过即上报
            limitDutration: 3000,
            // 网络状况
            network: null,
            //延迟请求resource时间(等待请求完成多久后开始监控)
            resourceDelay: 6000,
            //过滤掉的资源或者请求地址
            filter:[
                "baidu.com",  //一级域名
                "www.baidu.com", //二级域名
                "http://www.baidu.com/read" //完整链接
            ] 
        })
        //增加上传信息
        m.add({
            author:'superman'
        })
    }

调试

    npm run dev  //开发
    npm run server //启动本地服务器 测试发送延迟请求

    页面地址:http://localhost:3000/
    模拟请求地址:http://localhost:3001

目标

发现单个大体积或者下载慢的文件(慢加载),并上报
发现耗时过长请求接口,并上报
发现白屏过长的页面,并上报
发现首屏可操作时间过长的页面,并上报

监控指标

网络状况良好情况下,下载时间大于(可配置)的资源上报(找出有问题的请求资源链接)
文件体积过大(可配置)的资源上报(找出大文件)
网络状况良好的情况下,ajax请求时间大于(可配置)秒上报
针对script执行时间(dom解析过慢)的页面,进行监控和上报

监控方式

通过浏览器perfomance接口获取各项数据,计算各项指标
通过拦截全局fetch钩子,来统计请求过大,时间过长接口

浏览器对象可提供统计接口 timing

实现

开发性能统计js公共代码,页面引入
开发性能统计后台,统计异常页面


着手

对于统计网页的各项指标,引入外部资源统计其实并无多大意义。在外部资源加载完之前,js获取不到任何数据。事实上,浏览器已经提供了获取各项数据指标的接口

浏览器的performanceAPI是没有提供相关的脚本执行时间,
浏览器资源下载跟js解析执行可以不是在一个线程里。在外链script链接中有可能加defer,async,页面解析和资源下载可能同时进行,但是window.onload时间总是在js文件执行完成(同步)之后

虽然html4有defer,html5有async,会使得脚本执行时间错乱和不可控,但是页面的window.onload和监听“DOMContentLoaded”事件,可以统计页面的白屏时间(domLoading之前)和可操作时间(一般来讲 domComplete-dom结构加载完毕的时间,便是我们的用户可操作时间)来监控页面异常,用排除法来找出执行耗时过长的脚本


API调研

设备网络状况(navigator,有环境兼容问题)

caniuse

  • Navigation Timeing Api(只能在chrome浏览器实现)

  • 微信/QQ ua

  • appbridge API获取


Performance API 接口浏览器兼容

compatibility

Performance接口方法(通过window.performance获得)

performance.getEntries() //基于给定的 filter 返回一个 PerformanceEntry 对象的列表。
Performance.now() //返回一个表示从性能测量时刻开始经过的毫秒数 DOMHighResTimeStamp


PerformanceTiming 中有关时间节点的属性,按照先后顺序(值都是一个无符号long long 型的毫秒数)

navigationStart ,表征了从同一个浏览器上下文的上一个文档卸载(unload)结束时的UNIX时间戳。如果没有上一个文档,这个值会和PerformanceTiming.fetchStart相同

unloadEventStart 表征了unload事件抛出时的UNIX时间戳。如果没有上一个文档,or if the previous document, or one of the needed redirects, is not of the same origin, 这个值会返回0.

unloadEventEnd 表征了unload事件处理完成时的UNIX时间戳。如果没有上一个文档,or if the previous document, or one of the needed redirects, is not of the same origin, 这个值会返回0.

redirectStart 表征了第一个HTTP重定向开始时的UNIX时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0.

redirectEnd 表征了最后一个HTTP重定向完成时(也就是说是HTTP响应的最后一个比特直接被收到的时间)的UNIX时间戳。如果没有重定向,或者重定向中的一个不同源,这个值会返回0.

fetchStart 表征了浏览器准备好使用HTTP请求来获取(fetch)文档的UNIX时间戳。这个时间点会在检查任何应用缓存之前

domainLookupStart 表征了域名查询开始的UNIX时间戳。如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 PerformanceTiming.fetchStart一致。

domainLookupEnd 表征了域名查询结束的UNIX时间戳。如果使用了持续连接(persistent connection),或者这个信息存储到了缓存或者本地资源上,这个值将和 PerformanceTiming.fetchStart一致。

connectStart 返回HTTP请求开始向服务器发送时的Unix毫秒时间戳。如果使用持久连接(persistent connection),则返回值等同于fetchStart属性的值。

connectEnd 返回浏览器与服务器之间的连接建立时的Unix毫秒时间戳。如果建立的是持久连接,则返回值等同于fetchStart属性的值。连接建立指的是所有握手和认证过程全部结束。

secureConnectionStart 返回浏览器与服务器开始安全链接的握手时的Unix毫秒时间戳。如果当前网页不要求安全连接,则返回0。

requestStart 返回浏览器向服务器发出HTTP请求时(或开始读取本地缓存时)的Unix毫秒时间戳。

responseStart 返回浏览器从服务器收到(或从本地缓存读取)第一个字节时的Unix毫秒时间戳。如果传输层在开始请求之后失败并且连接被重开,该属性将会被数制成新的请求的相对应的发起时间。

responseEnd 返回浏览器从服务器收到(或从本地缓存读取,或从本地资源读取)最后一个字节时(如果在此之前HTTP连接已经关闭,则返回关闭时)的Unix毫秒时间戳。

domLoading 返回当前网页DOM结构开始解析时(即Document.readyState属性变为“loading”、相应的 readystatechange事件触发时)的Unix毫秒时间戳。

domInteractive 返回当前网页DOM结构结束解析、开始加载内嵌资源时(即Document.readyState属性变为“interactive”、相应的readystatechange事件触发时)的Unix毫秒时间戳。

domContentLoadedEventStart 返回当解析器发送DOMContentLoaded 事件,即所有需要被执行的脚本已经被解析时的Unix毫秒时间戳。

domContentLoadedEventEnd 返回当所有需要立即执行的脚本已经被执行(不论执行顺序)时的Unix毫秒时间戳。

domComplete 返回当前文档解析完成,即Document.readyState 变为 'complete'且相对应的readystatechange 被触发时的Unix毫秒时间戳。

loadEventStart 返回该文档下,load事件被发送时的Unix毫秒时间戳。如果这个事件还未被发送,它的值将会是0

loadEventEnd 返回当load事件结束,即加载事件完成时的Unix毫秒时间戳。如果这个事件还未被发送,或者尚未完成,它的值将会是0.

	//计算出统计所需要的时间
    let timing = performance.timing
    // DNS解析时间
    let dnsTime = timing.domainLookupEnd - timing.domainLookupStart
    //TCP建立时间
    let tcpTime = timing.connectEnd - timing.connectStart
    // 白屏时间
    let whiteTime = timing.domLoading - timing.navigationStart 
    //dom渲染完成时间
    let domTime = timing.domContentLoadedEventEnd - timing.navigationStart
    //页面onload时间
    let loadTime = timing.loadEventEnd - timing.navigationStart
    // 页面准备时间
    let readyTime = timing.fetchStart - timing.navigationStart
    // 页面重定向时间
    let redirectTime = timing.redirectEnd - timing.redirectStart 
    // unload时间
    let unloadTime = timing.unloadEventEnd - timing.unloadEventStart 
    //request请求耗时
    let requestTime = timing.responseEnd - timing.requestStart
    //页面解析dom耗时
    let analysisDomTime = timing.domComplete - timing.domInteractive
---
#### 为什么要统计网络状况
> **如果仅仅统计浏览器计算的下载时间,那网络状况不好的用户永远都会上报**

#### 为什么不能只统计大体积资源
**如果统计资源的大小,那么有大资源需求的网站永远在优化名单里。况且还可能包含了已经做了延迟加载、后台预加载优化的网站。** 
**so,只监控浏览器对于资源的下载时间或者只监控资源大小并没有实质的意义**
> 最终策略是统计大体积资源,但是可以设置filter。统计慢加载,但是只是在网络状态好的情况下列入上报名单。

---

#### 对于外链资源引用超时的情况
> 建议所有项目的非必须、非首屏渲染资源,尽量加async模式,或者放在body之后。

#### 对于全局ajax的请求时间监控
> 重写XmlHttpRequest,增加hooks,在返回时获取页面新增的请求,上报请求时间过长的resource

#### 浏览器对于img图片的处理
> 图片资源的加载优先级一般排在html,css,js等资源后面,会根据距离屏幕的位置确定不同的优先级,但是不影响页面继续加载。但是页面的window.onload会包含图片加载在内

#### 浏览器对于音频/视频媒体文件的处理
> 在浏览器解析到音频、视频资源后,异步进行下载,等到开始下载之后,并不会等待资源的canplay,会异步完成load

#### 对于动态插入的资源或者外部请求
> 动态添加静态资源暂不做处理,因为不影响用户界面体验。   
> 动态添加含有异步请求的脚本资源,是可以通过全局ajax钩子捕获的。