Skip to content

Instantly share code, notes, and snippets.

@RubaXa
Last active May 23, 2019 06:43
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save RubaXa/8662836 to your computer and use it in GitHub Desktop.
Save RubaXa/8662836 to your computer and use it in GitHub Desktop.
User Timing polyfill (http://www.w3.org/TR/user-timing/)
/**
* User Timing polyfill (http://www.w3.org/TR/user-timing/)
* @author RubaXa <trash@rubaxa.org>
*/
(function (window){
var
startOffset = Date.now ? Date.now() : +(new Date)
, performance = window.performance || {}
, _entries = []
, _marksIndex = {}
, _filterEntries = function (key, value){
var i = 0, n = _entries.length, result = [];
for( ; i < n; i++ ){
if( _entries[i][key] == value ){
result.push(_entries[i]);
}
}
return result;
}
, _clearEntries = function (type, name){
var i = _entries.length, entry;
while( i-- ){
entry = _entries[i];
if( entry.entryType == type && (name === void 0 || entry.name == name) ){
_entries.splice(i, 1);
}
}
}
;
if( !performance.now ){
performance.now = performance.webkitNow || performance.mozNow || performance.msNow || function (){
return (Date.now ? Date.now() : +(new Date)) - startOffset;
};
}
if( !performance.mark ){
performance.mark = performance.webkitMark || function (name){
var mark = {
name: name
, entryType: 'mark'
, startTime: performance.now()
, duration: 0
};
_entries.push(mark);
_marksIndex[name] = mark;
};
}
if( !performance.measure ){
performance.measure = performance.webkitMeasure || function (name, startMark, endMark){
startMark = _marksIndex[startMark].startTime;
endMark = _marksIndex[endMark].startTime;
_entries.push({
name: name
, entryType: 'measure'
, startTime: startMark
, duration: endMark - startMark
});
};
}
if( !performance.getEntriesByType ){
performance.getEntriesByType = performance.webkitGetEntriesByType || function (type){
return _filterEntries('entryType', type);
};
}
if( !performance.getEntriesByName ){
performance.getEntriesByName = performance.webkitGetEntriesByName || function (name){
return _filterEntries('name', name);
};
}
if( !performance.clearMarks ){
performance.clearMarks = performance.webkitClearMarks || function (name){
_clearEntries('mark', name);
};
}
if( !performance.clearMeasures ){
performance.clearMeasures = performance.webkitClearMeasures || function (name){
_clearEntries('measure', name);
};
}
// exports
window.performance = performance;
if( typeof define === 'function' && (define.amd || define.ajs) ){
define('performance', [], function (){ return performance });
}
})(window);
(function (){
module('performance');
function sleep(delay){
var start = performance.now();
while( true ){
if( performance.now() - start >= delay ){
break;
}
}
}
test('now', function (){
var start = performance.now();
sleep(1);
ok(performance.now() - start < 1.5);
});
test('performance.mark', function (){
performance.mark("foo");
sleep(5);
performance.mark("bar");
sleep(10);
performance.mark("baz");
equal(performance.getEntriesByType('mark').length, 3);
ok(performance.getEntriesByName('baz')[0].startTime - performance.getEntriesByName('bar')[0].startTime < 11, 'baz - bar');
ok(performance.getEntriesByName('bar')[0].startTime - performance.getEntriesByName('foo')[0].startTime < 6, 'bar - foo');
performance.clearMarks('bar');
equal(performance.getEntriesByType('mark').length, 2);
equal(performance.getEntriesByName('foo').length, 1);
equal(performance.getEntriesByName('bar').length, 0);
equal(performance.getEntriesByName('baz').length, 1);
performance.clearMarks();
equal(performance.getEntriesByType('mark').length, 0);
});
test('performance.measure', function (){
performance.mark("foo");
sleep(5);
performance.mark("bar");
performance.measure('foo_bar', 'foo', 'bar');
equal(performance.getEntriesByType('measure').length, 1);
ok(performance.getEntriesByName('foo_bar')[0].duration < 6, performance.getEntriesByName('foo_bar')[0].duration+'');
performance.mark("foo");
sleep(5);
performance.mark("bar");
sleep(5);
performance.mark("foo");
performance.measure('foo_bar', 'foo', 'bar');
equal(performance.getEntriesByType('measure').length, 2);
ok(performance.getEntriesByName('foo_bar')[1].duration < -5, performance.getEntriesByName('foo_bar')[1].duration+'');
performance.clearMarks();
performance.clearMeasures();
equal(performance.getEntriesByType('measure').length, 0);
});
})();
@sugendran
Copy link

Is there a licence for this polyfill? I'd like to include it in an open source library I have in mind.

@blackswanny
Copy link

@tompere
Copy link

tompere commented Aug 27, 2017

there are two issues with this implementation, related to lack of fail-safe logic in measureAPI:

  1. according to W3 user-timing specs, startMark and endMark are optional. Thus, the polyfill should implement fail safe for such use case.
  2. modern browsers support built-in/app-lifecycle marks to also be used as startMark and endMark in measure. This implementation assumes the above exists in internal cache (_marksIndex ), and access it without validating.

@PhonyWelder
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment