UNPKG

qoe-pps

Version:

this is a qoe project of pps

571 lines (416 loc) 21.6 kB
/*! usertiming v0.1.8 */ !function(a){"use strict";"undefined"==typeof a&&(a={}),"undefined"==typeof a.performance&&(a.performance={}),a._perfRefForUserTimingPolyfill=a.performance,a.performance.userTimingJsNow=!1,a.performance.userTimingJsNowPrefixed=!1,a.performance.userTimingJsUserTiming=!1,a.performance.userTimingJsUserTimingPrefixed=!1,a.performance.userTimingJsPerformanceTimeline=!1,a.performance.userTimingJsPerformanceTimelinePrefixed=!1;var b,c,d=[],e=[],f=null;if("function"!=typeof a.performance.now){for(a.performance.userTimingJsNow=!0,e=["webkitNow","msNow","mozNow"],b=0;b<e.length;b++)if("function"==typeof a.performance[e[b]]){a.performance.now=a.performance[e[b]],a.performance.userTimingJsNowPrefixed=!0;break}var g=+new Date;a.performance.timing&&a.performance.timing.navigationStart?g=a.performance.timing.navigationStart:"undefined"!=typeof process&&"function"==typeof process.hrtime&&(g=process.hrtime(),a.performance.now=function(){var a=process.hrtime(g);return 1e3*a[0]+1e-6*a[1]}),"function"!=typeof a.performance.now&&(Date.now?a.performance.now=function(){return Date.now()-g}:a.performance.now=function(){return+new Date-g})}var h=function(){},i=function(){},j=[],k=!1,l=!1;if("function"!=typeof a.performance.getEntries||"function"!=typeof a.performance.mark){for("function"==typeof a.performance.getEntries&&"function"!=typeof a.performance.mark&&(l=!0),a.performance.userTimingJsPerformanceTimeline=!0,d=["webkit","moz"],e=["getEntries","getEntriesByName","getEntriesByType"],b=0;b<e.length;b++)for(c=0;c<d.length;c++)f=d[c]+e[b].substr(0,1).toUpperCase()+e[b].substr(1),"function"==typeof a.performance[f]&&(a.performance[e[b]]=a.performance[f],a.performance.userTimingJsPerformanceTimelinePrefixed=!0);h=function(a){j.push(a),"measure"===a.entryType&&(k=!0)};var m=function(){k&&(j.sort(function(a,b){return a.startTime-b.startTime}),k=!1)};if(i=function(a,c){for(b=0;b<j.length;)j[b].entryType===a&&("undefined"==typeof c||j[b].name===c)?j.splice(b,1):b++},"function"!=typeof a.performance.getEntries||l){var n=a.performance.getEntries;a.performance.getEntries=function(){m();var b=j.slice(0);return l&&n&&(Array.prototype.push.apply(b,n.call(a.performance)),b.sort(function(a,b){return a.startTime-b.startTime})),b}}if("function"!=typeof a.performance.getEntriesByType||l){var o=a.performance.getEntriesByType;a.performance.getEntriesByType=function(c){if("undefined"==typeof c||"mark"!==c&&"measure"!==c)return l&&o?o.call(a.performance,c):[];"measure"===c&&m();var d=[];for(b=0;b<j.length;b++)j[b].entryType===c&&d.push(j[b]);return d}}if("function"!=typeof a.performance.getEntriesByName||l){var p=a.performance.getEntriesByName;a.performance.getEntriesByName=function(c,d){if(d&&"mark"!==d&&"measure"!==d)return l&&p?p.call(a.performance,c,d):[];"undefined"!=typeof d&&"measure"===d&&m();var e=[];for(b=0;b<j.length;b++)("undefined"==typeof d||j[b].entryType===d)&&j[b].name===c&&e.push(j[b]);return l&&p&&(Array.prototype.push.apply(e,p.call(a.performance,c,d)),e.sort(function(a,b){return a.startTime-b.startTime})),e}}}if("function"!=typeof a.performance.mark){for(a.performance.userTimingJsUserTiming=!0,d=["webkit","moz","ms"],e=["mark","measure","clearMarks","clearMeasures"],b=0;b<e.length;b++)for(c=0;c<d.length;c++)f=d[c]+e[b].substr(0,1).toUpperCase()+e[b].substr(1),"function"==typeof a.performance[f]&&(a.performance[e[b]]=a.performance[f],a.performance.userTimingJsUserTimingPrefixed=!0);var q={};"function"!=typeof a.performance.mark&&(a.performance.mark=function(b){var c=a.performance.now();if("undefined"==typeof b)throw new SyntaxError("Mark name must be specified");if(a.performance.timing&&b in a.performance.timing)throw new SyntaxError("Mark name is not allowed");q[b]||(q[b]=[]),q[b].push(c),h({entryType:"mark",name:b,startTime:c,duration:0})}),"function"!=typeof a.performance.clearMarks&&(a.performance.clearMarks=function(a){a?q[a]=[]:q={},i("mark",a)}),"function"!=typeof a.performance.measure&&(a.performance.measure=function(b,c,d){var e=a.performance.now();if("undefined"==typeof b)throw new SyntaxError("Measure must be specified");if(!c)return void h({entryType:"measure",name:b,startTime:0,duration:e});var f=0;if(a.performance.timing&&c in a.performance.timing){if("navigationStart"!==c&&0===a.performance.timing[c])throw new Error(c+" has a timing of 0");f=a.performance.timing[c]-a.performance.timing.navigationStart}else{if(!(c in q))throw new Error(c+" mark not found");f=q[c][q[c].length-1]}var g=e;if(d)if(g=0,a.performance.timing&&d in a.performance.timing){if("navigationStart"!==d&&0===a.performance.timing[d])throw new Error(d+" has a timing of 0");g=a.performance.timing[d]-a.performance.timing.navigationStart}else{if(!(d in q))throw new Error(d+" mark not found");g=q[d][q[d].length-1]}var i=g-f;h({entryType:"measure",name:b,startTime:f,duration:i})}),"function"!=typeof a.performance.clearMeasures&&(a.performance.clearMeasures=function(a){i("measure",a)})}"function"==typeof define&&define.amd?define([],function(){return a.performance}):"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=a.performance)}("undefined"!=typeof window?window:void 0); /** * QOE */ (function (w, p) { // p.mark('qoe_start'); var FIRST_PAGE_MARK = 'firstPage'; var SESSION_TEST = '_Q_test_'; var SESSION_QOE_HIT = '_QOE_HIT_'; var GROUP_API = 'http://msg.qy.net/qos'; var INTERFACE_API = 'https://msg.qy.net/qos'; var LIB_REGEXP = /\/\/static\.qiyi\.com\/js\/html5\/js\/lib\/lib\.(.*)+js\?sea1\.2\.min\.js/; var APP_REGEXP = /\/\/static\.iqiyi\.com\/js\/html5\/js\/page\/\w+\/\w{10}!app(\w*)+\.js/; var COMSCORE_REGEXP = /\/\/s?b\.scorecardresearch\.com\/beacon\.js/; var HM_REGEXP = /\/\/hm\.baidu\.com\/hm\.js\?5df871ab99f94347b23ca224fc7d013f/; var IRT_REGEXP = /\/\/iqiyi\.irs01\.com\/irt/; var ADS_REGEXP = /\/\/static\.iqiyi\.com\/js\/common\/ares\-/; var _QOE = {}; var _timing = p.timing; var userAgent = window.navigator; var Timing = { get responseStart () { return _timing.responseStart - _timing.navigationStart; }, get analysisStart () { return _timing.domLoading - _timing.navigationStart; }, get docLoad () { return _timing.responseEnd - _timing.navigationStart; }, get firstPaint () { return window.__first_paint_count; }, get analysisEnd () { return _timing.domInteractive - _timing.navigationStart; }, get domComplete () { return _timing.domComplete - _timing.navigationStart; }, get analysis1stPage () { var timing = Entries.byName(FIRST_PAGE_MARK)[0]; return timing ? timing.startTime : null; }, get prepareAnalysis () { return _timing.domLoading - _timing.responseStart; }, get networkInfomation () { var connection = window.navigator.connection || window.navigator.mozConnection return connection ? connection.effectiveType : ''; }, get browserVersion () { var version = userAgent.appVersion.replace(/.*AppleWebKit\/([\w.]+).*\..*/,"$1") return version; } } var Entries = { byName: function (name) { return p.getEntriesByName(name); }, byType: function (type) { return p.getEntriesByType(type || 'resource'); }, byFilter: function (filter, type) { return p.getEntriesByType(type || 'resource').filter(filter); }, byRegExp: function (reg, arg) { var entries; if (Object.prototype.toString.call(arg) === '[object Array]') { entries = arg } else { entries = p.getEntriesByType(arg || 'resource'); } var check = (function (reg) { switch (Object.prototype.toString.call(reg)) { case '[object RegExp]': return function (name) { return reg.test(name); }; break; case '[object String]': return function (name) { return name.indexOf(reg) !== -1; }; break; default: return null; } })(reg); return check ? entries.filter(function (item) { return check(item.name); }) : []; } } var Utils = { get checkHit () { try { w.sessionStorage.removeItem(SESSION_TEST); w.sessionStorage.setItem(SESSION_TEST, 1); w.sessionStorage.removeItem(SESSION_TEST); } catch (e) { console.error('sessionStorage error: ' + JSON.stringify(e)); return false; } var isHit = sessionStorage.getItem(SESSION_QOE_HIT); if (! isHit) { isHit = Math.round(Math.random() * 100); sessionStorage.setItem(SESSION_QOE_HIT, isHit); } return isHit >> 0 < 1; }, calculate: function (timings) { var ret = { duration: -1, LastResponse: -1 }; var arr = []; if (Object.prototype.toString.call(timings) === '[object Array]') { timings.forEach(function (timing) { timing.startTime > 0 && arr.push(timing.startTime); timing.responseEnd > 0 && arr.push(timing.responseEnd); }); var max = Math.max.apply(Math, arr); ret.duration = max - Math.min.apply(Math, arr); ret.LastResponse = max; } return ret; }, extend: function (origin, extend) { var properties = Object.getOwnPropertyNames(extend); properties.forEach(function (property) { origin[property] = extend[property]; }) }, send: function (url, params) { var src = url; var properties = Object.getOwnPropertyNames(params); src += '?' + 'p1=2_20_201&t=10&' + properties.map(function (property) { return property + '=' + params[property]; }).join('&'); if (debug) { src = src.replace(/((?:\?|\&)groupname=\w+?)(?=\&|$)/, '$1_LAN'); new Image().src = src; console.log('[QOE] debug: ' + src); } else { new Image().src = src; console.log('[QOE] sent: ' + src); } } } var get = { universal: function (entries) { return { docLoad: Timing.docLoad, analysisEnd: Timing.analysisEnd, domComplete: Timing.domComplete, responseStart: Timing.responseStart, analysisStart: Timing.analysisStart, syncJsAndCssOn1stPage: Utils.calculate(entries).duration, firstPaint: Timing.firstPaint, firstPage: Timing.analysis1stPage, networkInfomation: Timing.networkInfomation, browserVersion: Timing.browserVersion } }, js: function () { var common = { libLoad: LIB_REGEXP, appLoad: APP_REGEXP, comscore: COMSCORE_REGEXP, hm: HM_REGEXP, irt: IRT_REGEXP, ads: ADS_REGEXP } for (var o in common) { common[o] = Utils.calculate(Entries.byRegExp(common[o])).duration; } return common; }, ajax: function (ajaxes) { var arr = [], calc; ajaxes.forEach(function (ajax) { arr = arr.concat(Entries.byRegExp(ajax)); }); calc = Utils.calculate(arr); return { ajaxConsuming: calc.duration, ajaxReady: calc.LastResponse } }, } var QOE = function (debug) { this.activation = debug || Utils.checkHit; this.actionIndex = 0; }; QOE.prototype = { constructor: QOE, config: function (opts, callback) { if (this.activation) { if (! opts.pageName) { console.warn('[QOE] error: there seems to be no pagename'); } else { this.pageName = opts.pageName; this.ajax = opts.ajax || []; this.consuming = opts.consuming || []; this.extendParams = opts.extendParams || {}; callback && callback.call(this); } } }, mark: function (name, isAuto) { p.mark(name); var now = p.now(); if (isAuto) { _QOE[name] = now; } return now; }, measure: function (name, mark1, mark2, isAuto) { p.measure(name, mark1, mark2); var duration = Entries.byName(name)[0].duration; if (isAuto) { _QOE[name] = duration; } p.clearMeasures(name); return duration; }, syncResource: function () { this.syncJsAndCssOn1stPage = Entries.byFilter(function (item) { return item.initiatorType !== 'css' && item.initiatorType !== 'img'; }); }, asyncLoading: function (param) { return Math.ceil(param.domComplete - param.appInitialized); }, businessLogicLoading: function (param) { return Math.ceil(param.appInitializtion + param.componentsRegister + param.appLoad); }, asyncLoadComponent: function (param) { return Math.ceil(param.appInitialized - param.appInitializtion - param.componentsRegister - param.appLoad - param.analysisEnd); }, docAnalysis: function (param) { return Math.ceil(param.analysisEnd - param.firstPaint); }, transmission: function (param) { return Math.ceil(param.firstPaint); }, sendGroup: function () { this.mark('QOEPrepare'); this.set(get.universal(this.syncJsAndCssOn1stPage)); this.set(get.js()); this.set(get.ajax(this.ajax)); var params = { type: 'qoe', groupname: 'm_page_' + this.pageName, _: + new Date() }; Utils.extend(params, this.extendParams); this.mark('QOESend'); this.measure('QOERun', 'QOEPrepare', 'QOESend', true); var extendParam = { asy_load: this.asyncLoading(_QOE), bus_load: this.businessLogicLoading(_QOE), asyload_comp: this.asyncLoadComponent(_QOE), doc_ana: this.docAnalysis(_QOE), trans: this.transmission(_QOE) }; var baseData = { res_start: _QOE.responseStart, ana_start: _QOE.analysisStart, doc_load: _QOE.docLoad, fst_paint: _QOE.firstPaint, fst_page: _QOE.firstPage, app_load: _QOE.appLoad, com_reg: _QOE.componentsRegister, ana_end: _QOE.analysisEnd, app_init: _QOE.appInitializtion, dom_comp: _QOE.domComplete, ajax_ready: _QOE.ajaxReady, adjs_start: _QOE.ad_script_start, adjs_end: _QOE.ad_script_end, creg_start: _QOE.compsRegisterStart, fdl: _QOE.fangdaolian, src_auth: _QOE.sourceAuth, ad_req: _QOE.ad_request, pbtn_show: _QOE.playBtnShow, app_inited: _QOE.appInitialized, qoe_run: _QOE.QOERun, net_info: _QOE.networkInfomation, bro_ver: _QOE.browserVersion }; Utils.extend(baseData, extendParam); this.getApi(baseData, params, GROUP_API); }, sendSync: function () { this.mark('QOEPrepare'); var params = { type: 'qoe', groupname: 'm_page_' + this.pageName, _: + new Date() }; Utils.extend(params, {}); this.mark('QOESend'); this.measure('QOERun', 'QOEPrepare', 'QOESend', true); var syncParam = { cooksdk_dl: Math.ceil(_QOE.cooksdkDownload), cooksdk_exc: Math.ceil(_QOE.cooksdkExecute), fdl_dl: Math.ceil(_QOE.fangdaolianDownload), fdl_exc: Math.ceil(_QOE.fangdaolian), ad_dl: Math.ceil(_QOE.adDownload), ad_exc: Math.ceil(_QOE.ad_request) }; Utils.extend(syncParam, {}); this.getApi(syncParam, params, GROUP_API); }, sendAjax: function() { this.mark('QOEPrepare'); var params = { type: 'qoe', groupname: 'm_page_' + this.pageName, _: + new Date() }; Utils.extend(params, {}); this.mark('QOESend'); this.measure('QOERun', 'QOEPrepare', 'QOESend', true); var ajaxParam = { tmts_ajax: Math.ceil(_QOE.sourceAuth), dfp_to: Math.ceil(_QOE.dfpTimeout), set_src: Math.ceil(_QOE.playBtnShow), can_play: Math.ceil(_QOE.canPlayPreloaded), fst_play: Math.ceil(_QOE.videoTimeupdate) }; Utils.extend(ajaxParam, {}); this.getApi(ajaxParam, params, GROUP_API); }, getApi: function (arr, params, api) { var index = 0; for (var o in arr) { if (arr[o] && arr[o] > 0 && isFinite(arr[o])) { index += 1; params[o] = (typeof arr[o] === 'number') ? parseInt(arr[o].toFixed(2)) : 0; } else { console.warn('[QOE] missing: ' + o); } } if (index !== 0) { Utils.send(api, params); } }, sendIntreface: function (key, value) { if (typeof value === 'undefined') { var startMark = key + 'Start'; var endMark = key + 'End'; if (! Entries.byName(startMark).length) { console.warn('[QOE] send interface error: startMark is missing'); return; } else if (! Entries.byName(endMark).length) { console.warn('[QOE] send interface error: endMark is missing'); return; } else { value = this.measure(key, startMark, endMark); } } // if (value >> 0 <= 0) { // console.warn('[QOE] send interface error: value is negative'); // return; // } var api = INTERFACE_API; var params = { groupname: 'm_if_' + key } var format = JSON.parse(value); if (typeof format === 'object') { for (var i in format) { params[i] = typeof format[i] === 'number' ? parseInt(format[i].toFixed(2)) : format[i]; } } else { params[key] = typeof value === 'number' ? parseInt(value.toFixed(2)) : value; } Utils.send(api, params); }, sendAction: function () { // var t = p.now(); var consuming = this.consuming; var actionIndex = this.actionIndex; var entries = Entries.byFilter(function (item, index) { return index > actionIndex && (item.initiatorType === 'script' || item.initiatorType === 'xmlhttprequest'); }); consuming.forEach(function (item) { Entries.byRegExp(item.pattern, entries).forEach(function (_item) { this.sendIntreface(item.name, _item.duration); }, this); }, this) this.actionIndex = Entries.byType().length; // this.actionIndex = 0; // console.log(p.now() - t); }, set: function (obj) { Utils.extend(_QOE, obj); }, get: function (property) { if (property && _QOE[property]) { return _QOE[property]; } else if (property && ! _QOE[property]) { console.warn('there is no property called \'' + property + '\''); return null; } else { return _QOE; } } }; var debug = new RegExp('debugqoe_' + ((+ new Date()) / 1e6 | 0).toString(32)).test(location.search); w.__QOE__ = new QOE(debug); // p.mark('qoe_end'); // console.log(p.getEntriesByName('qoe_end')[0].startTime - p.getEntriesByName('qoe_start')[0].startTime); })(window, performance);