-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
134 lines (125 loc) · 3.98 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
var HRStopwatch = require('hrstopwatch')
, timeunit = require ('timeunit')
, intercept = require('fn-intercept')
, log = console.log
, DEFAULT_PREFIX = 'timeMe'
, enabled = true;
/*
* Globally configure the module
*
* `options.log` - the function that will log out the time msg.
*/
exports.configure = function(options) {
options = options || {};
log = 'function' === typeof(options.log) ? options.log : log;
enabled = 'boolean' === typeof(options.enabled) ? options.enabled : enabled;
}
exports.async = function(options, fn) {
return timeMe('async', options, fn);
}
exports.sync = function(options, fn) {
return timeMe('sync', options, fn);
}
exports.promise = function(options, fn) {
return timeMe('promise', options, fn);
}
function logMsg(options, msg, elapsed) {
if (!options.noLog) {
log(msg + " " + elapsed + "ms", {prefix: msg, elapsed: elapsed});
}
}
/*
* Wrap an async/sync function so that its total execution time
* can be recorded.
*
* `async` - whether or not the wrapped function is async
* `options.msg` {String} - Prefix to the timing message
* `options.index` {Integer} - (optional) the index of the callback argument
* in the wrapped func based at 0. Defaults to the last argument.
* `options.noLog` {Boolean} - (optional) whether to log out the message or not. Default is false.
* `fn` {Function} - the function to wrap and time
*/
function timeMe(mode, options, fn) {
var msg = DEFAULT_PREFIX;
if ("string" === typeof options) {
if ("function" !== typeof fn) {
return invalid("first arg string. 2nd should be func.");
}
msg = options;
options = {};
} else if ("function" === typeof options) {
fn = options;
options = {};
}
if (!enabled) {
return fn;
}
msg = options.msg || msg;
var index = options.index,
noLog = !!options.noLog,
__timee__;
if ('async' === mode) {
var watch;
__timee__ = intercept.async(fn, {index: index}, function() {
var args = sliceArgs(arguments);
watch = new HRStopwatch();
return args[0].apply(this, sliceArgs(args, 1));
}, function() {
var args = sliceArgs(arguments);
var elapsed = getTime(watch);
__timee__.lastTime = elapsed;
logMsg({noLog: noLog}, msg, elapsed);
args[0].apply(this, sliceArgs(args, 1));
});
} else if ('sync' === mode) {
__timee__ = intercept.sync(fn, function() {
var args = sliceArgs(arguments);
var watch = new HRStopwatch();
var result = args[0].apply(this, sliceArgs(args, 1));
var elapsed = getTime(watch);
__timee__.lastTime = elapsed;
logMsg(options, msg, elapsed);
return result;
});
} else if ('promise' === mode) {
__timee__ = intercept.sync(fn, function() {
var args = sliceArgs(arguments);
var watch = new HRStopwatch();
var p = args[0].apply(this, sliceArgs(args, 1));
p.then(function(result) {
var elapsed = getTime(watch);
__timee__.lastTime = elapsed;
logMsg(options, msg, elapsed);
return result;
});
return p;
});
} else {
throw new Error('Unknown mode: ' + mode);
}
return __timee__;
}
/*
* Helper to convert a watcher into ms
*/
function getTime(watch) {
return Math.floor(timeunit.nanoseconds.toMillis(watch.getTime()));
}
/*
* Warn the user nothing will happen because invalid args were passed
*/
function invalid(msg) {
console.warn("timeMe: function won't be timed: " + msg);
return function(){};
}
/*
* convert an arguments object into an array. We do it this way because
* mdn warns us not to use Array.prototype.slice.
*/
function sliceArgs(args, start) {
var array = [];
for (prop in args) {
if (!start || +prop >= start) array.push(args[prop]);
}
return array;
}