UNPKG

fedtools-utilities

Version:
360 lines (313 loc) 8.75 kB
/** * Node polyfill for UserTiming (http://www.w3.org/TR/user-timing/) * * Heavily inspired by: * Copyright 2013 Nic Jansma * http://nicj.net * https://github.com/nicjansma/usertiming.js * * Adapted to: * - only support nodejs * - pass our eslint rules * * Example: * * performance.mark('mark-1'); * // do something lenghty * performance.mark('mark-2'); * // do something else lenghty too * performance.mark('mark-3'); * * performance.measure('perf1', 'mark-1', 'mark-2'); * performance.measure('perf2', 'mark-2', 'mark-3'); * performance.measure('total', 'mark-1', 'mark-3'); * * // now you can find different performance mesures by their names: * console.log(performance.getEntriesByName('total')); * [{ entryType: 'measure', name: 'total', startTime: 0, duration: 284.568687 }] * */ var performance = {}, marks = {}, addToPerformanceTimeline, clearEntriesFromPerformanceTimeline, ensurePerformanceTimelineOrder, performanceTimeline = [], performanceTimelineRequiresSort = false, nowOffset = process.hrtime(); /** /* window.performance.now() shim /* http://www.w3.org/TR/hr-time/ */ performance.now = function () { var MILLI = 1000, NANO = 1000000, time = process.hrtime(nowOffset); return time[0] * MILLI + time[1] / NANO; }; /** /* PerformanceTimeline (PT) shims /* http://www.w3.org/TR/performance-timeline/ */ /** * Adds an object to our internal Performance Timeline array. */ addToPerformanceTimeline = function (obj) { performanceTimeline.push(obj); // // If we insert a measure, its startTime may be out of order // from the rest of the entries because the user can use any // mark as the start time. If so, note we have to sort it before // returning getEntries(); // if (obj.entryType === 'measure') { performanceTimelineRequiresSort = true; } }; /** * Ensures our PT array is in the correct sorted order (by startTime) */ ensurePerformanceTimelineOrder = function () { if (!performanceTimelineRequiresSort) { return; } // // Measures, which may be in this list, may enter the list in // an unsorted order. For example: // // 1. measure('a') // 2. mark('start_mark') // 3. measure('b', 'start_mark') // 4. measure('c') // 5. getEntries() // // When calling #5, we should return [a,c,b] because technically the start time // of c is "0" (navigationStart), which will occur before b's start time due to the mark. // performanceTimeline.sort(function (a, b) { return a.startTime - b.startTime; }); performanceTimelineRequiresSort = false; }; /** * Clears the specified entry types from our timeline array. * * @param {string} entryType Entry type (eg "mark" or "measure") * @param {string} [name] Entry name (optional) */ clearEntriesFromPerformanceTimeline = function (entryType, name) { // clear all entries from the perf timeline var i = 0; while (i < performanceTimeline.length) { if (performanceTimeline[i].entryType !== entryType) { // unmatched entry type i++; continue; } if (typeof name !== 'undefined' && performanceTimeline[i].name !== name) { // unmatched name i++; continue; } // this entry matches our criteria, remove it performanceTimeline.splice(i, 1); } }; /** * Gets all entries from the Performance Timeline. * http://www.w3.org/TR/performance-timeline/#dom-performance-getentries * * NOTE: This will only ever return marks and measures. * * @returns {PerformanceEntry[]} Array of PerformanceEntrys */ performance.getEntries = function () { var entries; ensurePerformanceTimelineOrder(); // get a copy of all of our entries entries = performanceTimeline.slice(0); return entries; }; /** * Gets all entries from the Performance Timeline of the specified type. * http://www.w3.org/TR/performance-timeline/#dom-performance-getentriesbytype * * NOTE: This will only work for marks and measures. * * @param {string} entryType Entry type (eg "mark" or "measure") * * @returns {PerformanceEntry[]} Array of PerformanceEntrys */ performance.getEntriesByType = function (entryType) { var i = 0, len, entries = []; // we only support marks/measures if (typeof entryType === 'undefined' || (entryType !== 'mark' && entryType !== 'measure')) { return []; } // see note in ensurePerformanceTimelineOrder() on why this is required if (entryType === 'measure') { ensurePerformanceTimelineOrder(); } // find all entries of entryType len = performanceTimeline.length; for (i = 0; i < len; i++) { if (performanceTimeline[i].entryType === entryType) { entries.push(performanceTimeline[i]); } } return entries; }; /** * Gets all entries from the Performance Timeline of the specified * name, and optionally, type. * http://www.w3.org/TR/performance-timeline/#dom-performance-getentriesbyname * * NOTE: This will only work for marks and measures. * * @param {string} name Entry name * @param {string} [entryType] Entry type (eg "mark" or "measure") * * @returns {PerformanceEntry[]} Array of PerformanceEntrys */ performance.getEntriesByName = function (name, entryType) { var i = 0, len, entries = []; if (entryType && entryType !== 'mark' && entryType !== 'measure') { return []; } // see note in ensurePerformanceTimelineOrder() on why this is required if (typeof entryType !== 'undefined' && entryType === 'measure') { ensurePerformanceTimelineOrder(); } // find all entries of the name and (optionally) type len = performanceTimeline.length; for (i = 0; i < len; i++) { if (typeof entryType !== 'undefined' && performanceTimeline[i].entryType !== entryType) { continue; } if (performanceTimeline[i].name === name) { entries.push(performanceTimeline[i]); } } return entries; }; /** * UserTiming mark * http://www.w3.org/TR/user-timing/#dom-performance-mark * * @param {string} markName Mark name */ performance.mark = function (markName) { var now = performance.now(); // mark name is required if (typeof markName === 'undefined') { throw new SyntaxError('Mark name must be specified'); } // mark name can't be a NT timestamp if (performance.timing && markName in performance.timing) { throw new SyntaxError('Mark name is not allowed'); } if (!marks[markName]) { marks[markName] = []; } marks[markName].push(now); // add to perf timeline as well addToPerformanceTimeline({ entryType: 'mark', name: markName, startTime: now, duration: 0 }); }; /** * UserTiming clear marks * http://www.w3.org/TR/user-timing/#dom-performance-clearmarks * * @param {string} markName Mark name */ performance.clearMarks = function (markName) { if (!markName) { // clear all marks marks = {}; } else { marks[markName] = []; } clearEntriesFromPerformanceTimeline('mark', markName); }; // } // if (typeof performance.measure !== "function") { /** * UserTiming measure * http://www.w3.org/TR/user-timing/#dom-performance-measure * * @param {string} measureName Measure name * @param {string} [startMark] Start mark name * @param {string} [endMark] End mark name */ performance.measure = function (measureName, startMark, endMark) { var duration, now = performance.now(), startMarkTime = 0, endMarkTime = now; if (typeof measureName === 'undefined') { throw new SyntaxError('Measure must be specified'); } // if there isn't a startMark, we measure from navigationStart to now if (!startMark) { // add to perf timeline as well addToPerformanceTimeline({ entryType: 'measure', name: measureName, startTime: 0, duration: now }); return; } if (startMark in marks) { startMarkTime = marks[startMark][marks[startMark].length - 1]; } else { throw new Error(startMark + ' mark not found'); } if (endMark) { endMarkTime = 0; if (endMark in marks) { endMarkTime = marks[endMark][marks[endMark].length - 1]; } else { throw new Error(endMark + ' mark not found'); } } // add to our measure array duration = endMarkTime - startMarkTime; // add to perf timeline as well addToPerformanceTimeline({ entryType: 'measure', name: measureName, startTime: startMarkTime, duration: duration }); }; /** * UserTiming clear measures * http://www.w3.org/TR/user-timing/#dom-performance-clearmeasures * * @param {string} measureName Measure name */ performance.clearMeasures = function (measureName) { clearEntriesFromPerformanceTimeline('measure', measureName); }; module.exports = performance;