@taraai/read-write
Version:
Synchronous NoSQL/Firestore for React
258 lines (213 loc) • 6.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = mark;
exports.resource = resource;
var _noop = _interopRequireDefault(require("lodash/noop"));
var _debug = _interopRequireDefault(require("debug"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const info = (0, _debug.default)('readwrite:profile');
if (info.enabled && _debug.default.enabled('readwrite:cache')) {
info(`Capturing Reducer & Firestore load times.
See results with 'readwrite()'.`);
}
let win;
try {
const nodeRequire = module[`require`].bind(module);
win = nodeRequire('perf_hooks');
} catch (e) {}
try {
win = window;
} catch (e) {}
const perf = win && win.performance;
function mark(marker) {
let context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
if (!_debug.default.enabled('readwrite:cache') || !_debug.default.enabled('readwrite:profile') || !perf) {
return _noop.default;
}
try {
const now = perf.now();
const start = `::readwrite/${marker}-${now}`;
perf.mark(start);
if (context) {
info(`${marker}.${context}`);
}
return () => {
perf.measure(`::readwrite/${marker}`, start);
};
} catch (err) {
return _noop.default;
}
}
function resource(meta, stringify) {
if (!_debug.default.enabled('readwrite:cache') || !_debug.default.enabled('readwrite:profile') || !perf) {
return _noop.default;
}
try {
const now = perf.now();
const marker = stringify(meta);
let start = `::readwrite.load/${marker}-${now}`;
perf.mark(start);
return function () {
let count = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
if (!start) return;
perf.measure(`::readwrite.load/${marker}.|${count}|`, start);
start = null;
};
} catch (err) {
return _noop.default;
}
}
if (win) {
win.readwriteStats = function () {
let force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
if (!_debug.default.enabled('readwrite:cache') || !_debug.default.enabled('readwrite:profile') || !perf) {
if (force) _debug.default.enable(typeof force === 'string' ? force : 'readwrite:*');
return;
}
const getMarks = _ref => {
let {
name
} = _ref;
return name.indexOf('::readwrite/') === 0;
};
const getLoads = _ref2 => {
let {
name
} = _ref2;
return name.indexOf('::readwrite.load/') === 0;
};
const duration = (stats, _ref3) => {
let {
duration,
name
} = _ref3;
if (stats[name]) {
stats[name].push(duration);
} else {
stats[name] = [duration];
}
return stats;
};
const formatTime = seconds => {
if (seconds < 1000) return seconds + 'ms';
if (seconds < 1000 * 60) return (seconds / 1000).toFixed(3) + 's';
return (seconds / (1000 * 60)).toFixed(3) + ' minutes';
};
const logStats = grouped => {
console.group(`Read Write Profiling`);
console.table(Object.keys(grouped).map(name => {
const arr = grouped[name];
const sum = arr.reduce((a, b) => a + b, 0);
return {
[name]: {
mean: parseFloat((sum / arr.length).toFixed(2)),
samples: arr.length,
min: parseFloat(arr.reduce((a, b) => a < b ? a : b, arr[0]).toFixed(2)),
max: parseFloat(arr.reduce((a, b) => a > b ? a : b, arr[0]).toFixed(2)),
sum: parseFloat(sum.toFixed(2))
}
};
}).reduce((result, item) => ({ ...result,
...item
})));
console.groupEnd();
};
const marks = performance.getEntriesByType('measure').filter(getMarks).reduce(duration, {});
logStats(marks);
const phases = ((last, phase) => _ref4 => {
let {
startTime,
duration,
name
} = _ref4;
if (last + 16 <= startTime) {
phase++;
}
const item = {
name,
start: parseFloat(startTime.toFixed(2)),
phase,
duration: formatTime(parseFloat(duration.toFixed(2))),
loaded: (/\|(\d+)\|/g.exec(name) || [0, 0])[1]
};
last = startTime;
return item;
})(false, 0);
const group = (arr, prop) => arr.reduce((stats, _ref5) => {
let {
phase,
name,
start,
duration,
loaded
} = _ref5;
if (!stats[phase]) {
stats[phase] = {};
}
stats[phase][name] = {
start,
duration,
loaded
};
return stats;
}, {});
const logPhases = phases => {
let last = 0;
console.group(`Firestore Collection Loads`);
Object.keys(phases).forEach(key => {
const start = Object.values(phases[key]).reduce((num, _ref6) => {
let {
start
} = _ref6;
return Math.min(num, start);
}, Number.MAX_VALUE);
console.group(`Phase ${key} +${Math.floor(start - last)}ms`);
console.table(phases[key]);
console.groupEnd();
last = start;
});
console.groupEnd();
};
const loads = performance.getEntriesByType('measure').filter(getLoads).map(phases);
logPhases(group(loads, 'phase'));
};
}
if (!Object.size) {
Object.size = obj => {
let bytes = 0;
const sizeOf = obj => {
if (obj !== null && obj !== undefined) {
switch (typeof obj) {
case 'number':
bytes += 8;
break;
case 'string':
bytes += obj.length * 2;
break;
case 'boolean':
bytes += 4;
break;
case 'object':
const objClass = Object.prototype.toString.call(obj).slice(8, -1);
if (objClass === 'Object' || objClass === 'Array') {
for (const key in obj) {
if (!obj.hasOwnProperty(key)) continue;
sizeOf(obj[key]);
}
} else bytes += obj.toString().length * 2;
break;
}
}
return bytes;
};
const formatByteSize = total => {
if (total < 1024) return total + ' bytes';
if (total < 1048576) return (total / 1024).toFixed(3) + ' KiB';
if (total < 1073741824) return (total / 1048576).toFixed(3) + ' MiB';
return (total / 1073741824).toFixed(3) + ' GiB';
};
return formatByteSize(sizeOf(obj));
};
}