qoe-pps
Version:
this is a qoe project of pps
571 lines (416 loc) • 21.6 kB
JavaScript
/*! 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);