block-timer
Advanced tools
Comparing version 0.1.0 to 0.1.1
300
index.js
@@ -6,11 +6,11 @@ /* | ||
function each(obj, iterator, context) { | ||
if (obj.forEach) { | ||
obj.forEach(iterator, context); | ||
} else { | ||
var keys = Object.keys(obj); | ||
for (var i = 0; i < keys.length; i++) { | ||
iterator.call(context, obj[keys[i]], keys[i], obj); | ||
} | ||
} | ||
return obj; | ||
if (obj.forEach) { | ||
obj.forEach(iterator, context); | ||
} else { | ||
var keys = Object.keys(obj); | ||
for (var i = 0; i < keys.length; i++) { | ||
iterator.call(context, obj[keys[i]], keys[i], obj); | ||
} | ||
} | ||
return obj; | ||
}; | ||
@@ -24,16 +24,16 @@ | ||
function isObject(arg) { | ||
return ('[object Object]' === Object.prototype.toString.call(arg)); | ||
return ('[object Object]' === Object.prototype.toString.call(arg)); | ||
} | ||
function isArray(arg) { | ||
return Array.isArray(arg); | ||
return Array.isArray(arg); | ||
} | ||
function length(arg) { | ||
return (isObject(arg) ? Object.keys(arg) : arg).length; | ||
return (isObject(arg) ? Object.keys(arg) : arg).length; | ||
} | ||
function commas(str) { | ||
str = '' + str; | ||
return str.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); | ||
str = '' + str; | ||
return str.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,'); | ||
} | ||
@@ -47,10 +47,10 @@ | ||
function newTimer() { | ||
return { | ||
start: Date.now() | ||
}; | ||
return { | ||
start: Date.now() | ||
}; | ||
} | ||
function endTimer(timer) { | ||
timer.end = Date.now(); | ||
timer.delta = timer.end - timer.start; | ||
timer.end = Date.now(); | ||
timer.delta = timer.end - timer.start; | ||
} | ||
@@ -64,27 +64,27 @@ | ||
function startById(timers, key, id) { | ||
if (!timers[key]) { | ||
timers[key] = {}; | ||
} | ||
if (!isObject(timers[key])) { | ||
throw new Error('Timer [' + key + '] initialised anonymously then called with an id.'); | ||
} | ||
if (timers[key][id] && timers[key][id].end) { | ||
throw new Error('Timer [' + key + '], id [' + id + '] started more than once.'); | ||
} | ||
timers[key][id] = newTimer(); | ||
if (!timers[key]) { | ||
timers[key] = {}; | ||
} | ||
if (!isObject(timers[key])) { | ||
throw new Error('Timer [' + key + '] initialised anonymously then called with an id.'); | ||
} | ||
if (timers[key][id] && timers[key][id].end) { | ||
throw new Error('Timer [' + key + '], id [' + id + '] started more than once.'); | ||
} | ||
timers[key][id] = newTimer(); | ||
} | ||
function stopById(timers, key, id) { | ||
if (!timers[key] || !timers[key][id] || timers[key][id].end) { | ||
throw new Error('Timer [' + key + '], id [' + id + '] stopped more than once.'); | ||
} | ||
endTimer(timers[key][id]); | ||
if (!timers[key] || !timers[key][id] || timers[key][id].end) { | ||
throw new Error('Timer [' + key + '], id [' + id + '] stopped more than once.'); | ||
} | ||
endTimer(timers[key][id]); | ||
} | ||
@@ -98,27 +98,27 @@ | ||
function startByIndex(timers, key) { | ||
if (!timers[key]) { | ||
timers[key] = []; | ||
} | ||
if (!isArray(timers[key])) { | ||
throw new Error('Timer [' + key + '] initialised with an id then called anynomously.'); | ||
} | ||
if (timers[key].length && timers[key][timers[key].length - 1].end) { | ||
throw new Error('Timer [' + key + '] started again without being stopped.'); | ||
} | ||
timers[key].push(newTimer()); | ||
if (!timers[key]) { | ||
timers[key] = []; | ||
} | ||
if (!isArray(timers[key])) { | ||
throw new Error('Timer [' + key + '] initialised with an id then called anynomously.'); | ||
} | ||
if (timers[key].length && timers[key][timers[key].length - 1].end) { | ||
throw new Error('Timer [' + key + '] started again without being stopped.'); | ||
} | ||
timers[key].push(newTimer()); | ||
} | ||
function stopByIndex(timers, key) { | ||
if (!timers[key] || !timers[key].length || timers[key][timers[key].length - 1].end) { | ||
throw new Error('Timer [' + key + '] stopped without being started.'); | ||
} | ||
endTimer(timers[key][timers[key].length - 1]); | ||
if (!timers[key] || !timers[key].length || timers[key][timers[key].length - 1].end) { | ||
throw new Error('Timer [' + key + '] stopped without being started.'); | ||
} | ||
endTimer(timers[key][timers[key].length - 1]); | ||
} | ||
@@ -132,66 +132,138 @@ | ||
function Timer() { | ||
// Ensure a new instance has been created. | ||
// Calling Timer as a function will return a new instance instead. | ||
if (!(this instanceof Timer)) { | ||
return new Timer(); | ||
} | ||
var timers = {}, | ||
timersById = {}; | ||
/** | ||
* Starts a timer by key (or key + id) | ||
*/ | ||
this.start = function(key, id) { | ||
if (id) { | ||
startById(timers, key, id); | ||
} else { | ||
startByIndex(timers, key); | ||
} | ||
return this; | ||
} | ||
/** | ||
* Stops a timer by key (or key + id) | ||
*/ | ||
this.stop = function(key, id) { | ||
if (id) { | ||
stopById(timers, key, id); | ||
} else { | ||
stopByIndex(timers, key); | ||
} | ||
return this; | ||
} | ||
/** | ||
* Formats the value of all timers as a string | ||
*/ | ||
this.toString = | ||
this.inspect = function() { | ||
var output = []; | ||
each(timers, function(timer, key) { | ||
var total = 0, | ||
str = '* ' + key + ': '; | ||
each(timer, function(i) { | ||
total += i.delta; | ||
}); | ||
var times = length(timer); | ||
if (times > 1) { | ||
str += commas(times) + ' x ' + commas(Math.round(total / times)) + 'ms = ' + commas(total) + 'ms'; | ||
} else { | ||
str += commas(total) + 'ms'; | ||
} | ||
output.push(str); | ||
}); | ||
return output.length ? 'TIMER RESULTS:\n' + output.join('\n') + '\n' : 'NO TIMERS TO OUTPUT'; | ||
} | ||
// Ensure a new instance has been created. | ||
// Calling Timer as a function will return a new instance instead. | ||
if (!(this instanceof Timer)) { | ||
return new Timer(); | ||
} | ||
} | ||
var timers = {}, | ||
timersById = {}; | ||
// Logs the timer output to the console | ||
Timer.prototype.log = function() { | ||
console.log(this); | ||
return this; | ||
} | ||
this.start = function(key, id) { | ||
// Replaces a Timer with a Stub | ||
Timer.prototype.stub = function() { | ||
this.isStub = true; | ||
['start', 'stop', 'log', 'inspect', 'toString'].forEach(function(i) { | ||
this[i] = Timer.Stub.prototype[i]; | ||
}, this); | ||
return this; | ||
} | ||
if (id) { | ||
startById(timers, key, id); | ||
} else { | ||
startByIndex(timers, key); | ||
} | ||
// Returns a new Timer instance | ||
Timer.create = function() { | ||
return new Timer(); | ||
} | ||
return this; | ||
// Returns a new Timer.Stub instance | ||
Timer.stub = function() { | ||
return new Timer.Stub(); | ||
} | ||
} | ||
/** | ||
* Stub Class | ||
* | ||
* Provides a simple way to disable the timer and remove any overhead | ||
* | ||
* Replaces the API with simple "do nothing" versions of each function | ||
*/ | ||
this.stop = function(key, id) { | ||
Timer.Stub = function() { | ||
// Ensure a new instance has been created. | ||
// Calling Timer.Stub as a function will return a new instance instead. | ||
if (!(this instanceof Timer.Stub)) { | ||
return new Timer.Stub(); | ||
} | ||
this.isStub = true; | ||
} | ||
if (id) { | ||
stopById(timers, key, id); | ||
} else { | ||
stopByIndex(timers, key); | ||
} | ||
Timer.Stub.prototype.start = | ||
Timer.Stub.prototype.stop = | ||
Timer.Stub.prototype.log = function() { | ||
return this; | ||
} | ||
return this; | ||
Timer.Stub.prototype.inspect = | ||
Timer.Stub.prototype.toString = function() { | ||
return ''; | ||
} | ||
} | ||
this.toString = this.inspect = function() { | ||
/** | ||
* Exports the Timer class | ||
*/ | ||
var output = []; | ||
each(timers, function(timer, key) { | ||
var total = 0, | ||
str = '* ' + key + ': '; | ||
each(timer, function(i) { | ||
total += i.delta; | ||
}); | ||
var times = length(timer); | ||
if (times > 1) { | ||
str += commas(times) + ' x ' + commas(Math.round(total / times)) + 'ms = ' + commas(total) + 'ms'; | ||
} else { | ||
str += commas(total) + 'ms'; | ||
} | ||
output.push(str); | ||
}); | ||
return output.length ? 'TIMER RESULTS:\n' + output.join('\n') + '\n' : 'NO TIMERS TO OUTPUT'; | ||
} | ||
} | ||
var exports = module.exports = Timer; |
{ | ||
"name": "block-timer", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "Timer utility for timing blocks of code that are run one or more times", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
142
README.md
@@ -1,6 +0,9 @@ | ||
block-timer | ||
Block Timer | ||
=========== | ||
A node.js timer implementation for timing blocks of code that are run one or more times | ||
A node.js timer implementation for timing blocks of code that are run one or more times. | ||
This is useful to discover how long certain blocks of your code take, and / or how many times they are run, without specifically being tied to certain functions or your stack trace. | ||
## Installation | ||
@@ -10,2 +13,135 @@ | ||
npm install --save block-timer | ||
``` | ||
``` | ||
## Usage | ||
Create a `new Timer()` instance and then start and stop named timer blocks on it. | ||
When you are done, call `timer.log()`, output `timer.toString()` or simply `console.log(timer)` to see the results. | ||
Each named timer block can be run multiple times in one of two modes: | ||
* sequentially (start, stop, start, stop...) | ||
* in parallel (each run is given an id) | ||
When a timer is run multiple times, the total number of timers run, total time taken and average timer per run will be displayed in the results. | ||
*Remember that parallel timers may run at the same time, which will result in overlap when calculating the total time taken; i.e. 5 timers running at the same time for 1 second each will add up to 5 seconds total, when the real time elapsed is 1 second* | ||
If a named block is run sequentially and started while already running, or stopped while not running, an error will be thrown. | ||
You cannot mix sequential and parallel modes for a single named timer block. | ||
### Creating a Timer Instance | ||
*Assume there's something that takes 1ms after each timer start* | ||
``` | ||
var Timer = require('block-timer'); | ||
var timer = new Timer(); | ||
// or | ||
var timer = Timer.create(); | ||
``` | ||
### Sequential Timers | ||
``` | ||
timer.start('block 1'); | ||
for (var i = 0; i <= 5; i++) { | ||
timer.start('block 2'); | ||
timer.stop('block 2'); | ||
} | ||
timer.stop('block 1'); | ||
console.log(timer); | ||
``` | ||
Will display: | ||
``` | ||
TIMER RESULTS: | ||
* block 1: 6ms | ||
* block 2: 5 x 1ms = 5ms | ||
``` | ||
### Parallel Timers | ||
*Assume there's something async that takes 1ms after each timer start* | ||
``` | ||
timer.start('block 1'); | ||
for (var i = 0; i < 5; i++) { | ||
timer.start('block 2', i); | ||
} | ||
for (var i = 0; i < 5; i++) { | ||
timer.stop('block 2', i); | ||
} | ||
timer.stop('block 1'); | ||
console.log(timer); | ||
``` | ||
Will display: | ||
``` | ||
TIMER RESULTS: | ||
* block 1: 2ms | ||
* block 2: 5 x 1ms = 5ms | ||
``` | ||
### Disabling the Timer | ||
You can disable the timer by calling `timer.stub()` or by using an instance of `new Timer.Stub()` instead. | ||
This provides an easy way of removing the timer and any overhead it creates, without actually commenting it out or removing it from your code. | ||
## API | ||
`new Timer()` or `Timer.create()` returns a new **Timer** instance | ||
`timer.start(name)` starts (or restarts) a sequential timer | ||
`timer.start(name, id)` starts a parallel timer by id | ||
`timer.stop(name)` stops a sequential timer | ||
`timer.stop(name, id)` stops a parallel timer by id | ||
`timer.toString()` returns the formatted results of all timers | ||
`timer.log()` logs the formatted results to the console | ||
### Stub API | ||
`new Timer.Stub()` or `Timer.stub()` returns a new **Timer.Stub** instance | ||
`timer.stub()` replaces all methods with stubs in an existing Timer instance | ||
Stubs match the real `Timer` API but do nothing, except for `stub.toString()` which returns an empty string. | ||
License | ||
======= | ||
The MIT License (MIT) | ||
Copyright (c) 2014 Jed Watson | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11455
189
147