'use strict';
const performanceNow = require('performance-now');
const fs = require('fs');
const stubber = require('./stubber');
const ErrorLib = require('./ErrorLib');
/**
* @class
*/
class BluebirdPromiseProfiler {
/**
* @constructor
*/
constructor () {
// check for bluebird promise dependency
let bluebirdPromiseUsed = null;
try {
bluebirdPromiseUsed = require(`../../bluebird`);
}
catch (e) {
ErrorLib.throwError(ErrorLib.errorMap.PromiseNotFound);
}
if (!bluebirdPromiseUsed.version || typeof bluebirdPromiseUsed.resolve !== 'function' || !(bluebirdPromiseUsed.resolve() instanceof bluebirdPromiseUsed)) {
ErrorLib.throwError(ErrorLib.errorMap.PromiseTypeError);
}
this._promise = bluebirdPromiseUsed;
this._profilerResult = {};
this._spreadStub = null;
this._thenStub = null;
this._catchStub = null;
}
/**
* Returns back the profiler result as json.
* @returns {{}} Profiler Result is returned which a json with key as promise name and value as its execution time in milliseconds.
*/
getProfilerResult () {
delete this._profilerResult[''];
return this._profilerResult;
}
/**
* Starts profiling on bluebird promise.
*/
startProfiling () {
const self = this;
try {
this._spreadStub = stubber.stub(self._promise.prototype, 'spread', function spreadProfiler () {
const promiseIndex = self._spreadStub.callCount - 1;
const execFunction = self._spreadStub.callingArgs[promiseIndex][0];
const functionName = execFunction.name;
const startTime = performanceNow();
return this.all()._then((result) => {
self._profilerResult[functionName] = performanceNow() - startTime;
return execFunction(...result);
});
});
this._thenStub = stubber.stub(self._promise.prototype, 'then', function thenProfiler () {
const promiseIndex = self._thenStub.callCount - 1;
const execFunction = self._thenStub.callingArgs[promiseIndex][0];
const functionName = execFunction.name;
const startTime = performanceNow();
return this._then((result) => {
self._profilerResult[functionName] = performanceNow() - startTime;
return this._then(execFunction);
});
});
this._catchStub = stubber.stub(self._promise.prototype, 'catch', function catchProfiler () {
const promiseIndex = self._catchStub.callCount - 1;
const execFunction = self._catchStub.callingArgs[promiseIndex][0];
const functionName = execFunction.name;
const startTime = performanceNow();
return this._then(undefined, (result) => {
self._profilerResult[functionName] = performanceNow() - startTime;
return this._then(undefined, execFunction);
});
});
}
catch (e) {}
}
/**
* Stops profiling on bluebird promise.
*/
stopProfiling () {
if (this._spreadStub !== null && this._thenStub !== null && this._catchStub !== null) {
this._spreadStub.restore();
this._thenStub.restore();
this._catchStub.restore();
}
};
/**
* Writes the profiler result to a .json file.
* @param {string} fullPath - Specify the full path with .json extension.
*/
writeProfilerResultToFile (fullPath = './output.json') {
const writeFile = this._promise.promisify(fs.writeFile);
return writeFile(fullPath, JSON.stringify(this._profilerResult, null, 4), 'utf8');
};
/**
* Resets profiler result, this does not stop further profiling.
*/
resetProfiler () {
this._profilerResult = {};
};
}
module.exports = new BluebirdPromiseProfiler();