Repository: Krb686/nanotimer Branch: master Commit: 6ec54f485bf6 Files: 7 Total size: 33.2 KB Directory structure: gitextract_1lw6oqm4/ ├── .gitignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── lib/ │ └── nanotimer.js ├── package.json └── test/ └── test-nanotimer.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .settings .project node_modules misc ================================================ FILE: .travis.yml ================================================ language: node_js # test on node version 0.10.35 node_js: - 0.10.35 ================================================ FILE: LICENSE.txt ================================================ Copyright (c) 2013-2015, Kevin Briggs Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: README.md ================================================ # nanotimer # Current Version - 0.3.15 ![](https://api.travis-ci.org/Krb686/nanoTimer.png) [![NPM](https://nodei.co/npm/nanotimer.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/nanotimer/) A much higher accuracy timer object that makes use of the node.js [hrtime](http://nodejs.org/api/process.html#process_process_hrtime) function call. The nanotimer recreates the internal javascript timing functions with higher resolution. ## Note - 1) With the normal timing functions, instead of dealing with the obscurities of multiple setTimeout and setInterval calls, now there is a concrete timer object, each of which can handle exactly 1 timeOut and setInterval task. This also means a reference is not needed to clear an interval since each timer object is unique. - 2) Timer objects use the non-blocking feature **setImmediate** for time counting and synchronization. This requires node v0.10.13 or greater - 3) Errors in timing are non-cumulative. For example when using the setInterval command, the timer counts and compares the time difference since starting against the interval length specified and if it has run past the interval, it resets. If the code had an error of 1 millisecond delay, the timer would actually count to 1001 milliseconds before resetting, and that 1 millisecond error would propagate through each cycle and add up very quickly! To solve that problem, rather than resetting the interval variable each cycle, it is instead incremented with each cycle count. So on the 2nd cycle, it compares to 2000 milliseconds, and it may run to 2001. Then 3000 milliseconds, running to 3001, and so on. This is only limited by the comparison variable potentially overflowing, so I somewhat arbitrarily chose a value of 8 quadrillion (max is roughly 9 quadrillion in javascript) before it resets. Even using nanosecond resolution however, the comparison variable would reach 8 quadrillion every 8 million seconds, or every 93.6ish days. ## Usage ```js var NanoTimer = require('nanotimer'); var timerA = new NanoTimer(); ``` Each nanotimer object can run other functions that are already defined. This can be done in 2 ways; with either a literal function object, or with a function declaration. ### by function object ```js var NanoTimer = require('nanotimer'); var timerObject = new NanoTimer(); var countToOneBillion = function () { var i = 0; while(i < 1000000000){ i++; } }; var microsecs = timerObject.time(countToOneBillion, '', 'u'); console.log(microsecs); ``` or something like this: ### by function declaration ```js var NanoTimer = require('nanotimer'); function main(){ var timerObject = new NanoTimer(); var microsecs = timerObject.time(countToOneBillion, '', 'u'); console.log(microsecs); } function countToOneBillion(){ var i = 0; while(i < 1000000000){ i++; } } main(); ``` ## Full example ```js var NanoTimer = require('nanotimer'); var count = 10; function main(){ var timer = new NanoTimer(); timer.setInterval(countDown, '', '1s'); timer.setTimeout(liftOff, [timer], '10s'); } function countDown(){ console.log('T - ' + count); count--; } function liftOff(timer){ timer.clearInterval(); console.log('And we have liftoff!'); } main(); ``` ### In the example above, the interval can also be cleared another way rather than having to pass in the timer object to the liftOff task. Instead, it can be done by specifying a callback to setTimeout, since the timer object will exist in that scope. Like so: ```js timer.setTimeout(liftOff, '', '10s', function(){ timer.clearInterval(); }); ``` ## .setTimeout(task, args, timeout, [callback]) * **task** * The function or task to run. Can be either a literal function object or reference to a function declaration. * **args** * An array of arguments to pass to **task**, or an empty string, **''** , if there are none. Note, even a single argument must be passed as an element in an array. * Ex. ['someString', 5, someVariable] * **timeout** * The amount of time to wait before calling **task**. This is a string containing a non-zero integer concatenated with one of 4 possible unit specifiers. * Unit specifiers are: * **s** = seconds * **m** = milliseconds * **u** = microseconds * **n** = nanoseconds * Ex. '500s', '37u', '45n' * **[callback]]** * The optional callback function to execute after the timeout has triggered. ```js console.log("It's gonna be legen-wait for it..."); timerA.setTimeout(dary, '', '2s'); function dary(){ console.log("dary!!"); } ``` ## .setInterval(task, args, interval, [callback]) * **task** * The function or task to run. Can be either a literal function object or reference to a function declaration. * **args** * An array of arguments to pass to **task**, or an empty string, **''** , if there are none. Note, even a single argument must be passed as an element in an array. * Ex. ['someString', 5, someVariable] * **interval** * The interval of time to wait between each call of **task**. This is a string containing a non-zero integer concatenated with one of 4 possible unit specifiers. * Unit specifiers are: * **s** = seconds * **m** = milliseconds * **u** = microseconds * **n** = nanoseconds * Ex. '500s', '37u', '45n' * **Note**: * If **interval** is specified as 0, the timer will run **task** as fast as possible. * This function is self correcting, error does not propagate through each cycle, as described above. * **[callback]]** * The optional callback function to execute after the timeout has triggered. ```js timerA.setInterval(task, '100m', function(err) { if(err) { //error } }); ``` ## .time(task, args, format, [callback]) * **task** * The function or task to run. Can be either a literal function object or reference to a function declaration. * **args** * An array of arguments to pass to **task**, or an empty string, **''** , if there are none. Note, even a single argument must be passed as an element in an array. * Ex. ['someString', 5, someVariable] * **format** * A single unit specifier indicating the format of the data to be returned. * Unit specifiers: * **s** = seconds * **m** = milliseconds * **u** = microseconds * **n** = nanoseconds * Ex. '500s', '37u', '45n' * **[callback]** * The optional callback function to execute after the time call has triggered. ### Synchronous Example: ```js var runtimeSeconds = timerA.time(doMath, '', 'u'); function doMath(){ //do math } ``` ### Asynchronous Use: To time something asynchronous, you only need to do these 3 things: 1. create a small wrapper function around the asynchronous task. 2. make the wrapper function take *callback* as a parameter. 3. manually call the *callback* parameter inside the callback of the asynchronous task. It's essentially a chain of callbacks, which is probably already familiar to you. Here's an example that times how long it takes to read a file. Suppose you're using node.js's fs.ReadFile, which is asynchronous, then create a wrapper like so: ```js var NanoTimer = require('nanotimer'); var fs = require('fs'); var timer = new NanoTimer(); timer.time(loadFile, '', 'u', function(time){ console.log("It took " + time + " microseconds to read that file!"); }); function loadFile(callback){ fs.readFile('testReadFile.js', function(err, data){ if(err) throw err; console.log(data); callback(); }); } ``` ## .clearInterval() * Clears current running interval ```js timer.clearInterval(); ``` ## .clearTimeout() * Clears current running timeOut ```js timer.clearTimeout(); ``` ## .hasTimeout() * Returns true if the timer currently has a scheduled timeout, or false otherwise ```js timer.hasTimeout(); ``` # Logging * Added preliminary logging feature. If a timer is created by passing in 'log', it will enable verbose logging from the timer, so you can figure out the real amount of time being taken for setTimeout or setInterval * Currently only works on setInterval, and displays the 'cycle time', or real interval time to demonstrate how error does not propagate. This will be further expanded on. # Tests * Test suite used is mocha. * Tests also require **should** * In order for the test to perform properly, the timeout must be altered. * I prefer running tests with `mocha -R spec -t 10000` ![](https://raw.github.com/Krb686/nanotimer/master/test/nanotimer_0_2_6_test_partial.png "Test Results") # Performance Version 0.3.1 brings about a potentially massive performance boost over previous versions. Previous versions used a setImmediate loop running as fast as possible for checking when to execute, inside setTimeout and setInterval. In 0.3.1, this has changed when using an intervalTime (setInterval), or delayTime (setTimeout) that is longer than 25ms. Execution will be deferred to the standard javascript setTimeout, aimed for 25ms before scheduled execution, where the setImmediate loop will resume. The assumed error of javascript's setTimeout is 25ms. Below is a test case with setInterval set to 1 second. ![](https://raw.github.com/Krb686/nanotimer/master/test/nanotimer_non_deferred.png "Non-Deferred") ![](https://raw.github.com/Krb686/nanotimer/master/test/nanotimer_deferred.png "Deferred") ================================================ FILE: lib/nanotimer.js ================================================ function NanoTimer(log){ var version = process.version; var major = version.split('.')[0]; major = major.split('v')[1]; var minor = version.split('.')[1]; if ((major == 0) && (minor < 10)){ console.log('Error: Please update to the latest version of node! This library requires 0.10.x or later'); process.exit(0); } //Time reference variables this.intervalT1 = null; this.timeOutT1 = null; this.intervalCount = 1; //Deferred reference indicator variables. Indicate whether the timer used/will use the deferred call. ie - delay/interval > 25ms this.deferredInterval = false; this.deferredTimeout = false; //Deferred reference variables. Used to clear the native js timeOut calls this.deferredTimeoutRef = null; this.deferredIntervalRef = null; //Callback reference variables. Used to be able to still successfully call callbacks when timeouts or intervals are cleared. this.timeoutCallbackRef = null; this.intervalCallbackRef = null; //Immediate reference variables. Used to clear functions scheduled with setImmediate from running in the event timeout/interval is cleared. this.timeoutImmediateRef = null; this.intervalImmediateRef = null; this.intervalErrorChecked = false; this.intervalType = ""; this.timeoutTriggered = false; if(log){ this.logging = true; } } NanoTimer.prototype.time = function(task, args, format, callback){ //Asynchronous task if(callback){ var t1 = process.hrtime(); if(args){ args.push(function(){ var time = process.hrtime(t1); if(format == 's'){ callback(time[0] + time[1]/1000000000); } else if (format == 'm'){ callback(time[0]*1000 + time[1]/1000000); } else if (format == 'u'){ callback(time[0]*1000000 + time[1]/1000); } else if (format == 'n'){ callback(time[0]*1000000000 + time[1]); } else { callback(time); } }); task.apply(null, args); } else { task(function(){ var time = process.hrtime(t1); if(format == 's'){ callback(time[0] + time[1]/1000000000); } else if (format == 'm'){ callback(time[0]*1000 + time[1]/1000000); } else if (format == 'u'){ callback(time[0]*1000000 + time[1]/1000); } else if (format == 'n'){ callback(time[0]*1000000000 + time[1]); } else { callback(time); } }); } //Synchronous task } else { var t1 = process.hrtime(); if(args){ task.apply(null, args); } else{ task(); } var t2 = process.hrtime(t1); if(format == 's'){ return t2[0] + t2[1]/1000000000; } else if (format == 'm'){ return t2[0]*1000 + t2[1]/1000000; } else if (format == 'u'){ return t2[0]*1000000 + t2[1]/1000; } else if (format == 'n'){ return t2[0]*1000000000 + t2[1]; } else { return process.hrtime(t1); } } }; NanoTimer.prototype.setInterval = function(task, args, interval, callback){ if(!this.intervalErrorChecked){ //Task error handling if(!task){ console.log("A task function must be specified to setInterval"); process.exit(1); } else { if(typeof(task) != "function"){ console.log("Task argument to setInterval must be a function reference"); process.exit(1); } } //Interval error handling if(!interval){ console.log("An interval argument must be specified"); process.exit(1); } else { if(typeof(interval) != "string"){ console.log("Interval argument to setInterval must be a string specified as an integer followed by 's' for seconds, 'm' for milli, 'u' for micro, and 'n' for nanoseconds. Ex. 2u"); process.exit(1); } } //This ref is used if deferred timeout is cleared, so the callback can still be accessed if(callback){ if(typeof(callback) != "function"){ console.log("Callback argument to setInterval must be a function reference"); process.exit(1); } else { this.intervalCallbackRef = callback; } } this.intervalType = interval[interval.length-1]; if(this.intervalType == 's'){ this.intervalTime = interval.slice(0, interval.length-1) * 1000000000; } else if(this.intervalType == 'm'){ this.intervalTime = interval.slice(0, interval.length-1) * 1000000; } else if(this.intervalType == 'u'){ this.intervalTime = interval.slice(0, interval.length-1) * 1000; } else if(this.intervalType == 'n'){ this.intervalTime = interval.slice(0, interval.length-1); } else { console.log('Error with argument: ' + interval + ': Incorrect interval format. Format is an integer followed by "s" for seconds, "m" for milli, "u" for micro, and "n" for nanoseconds. Ex. 2u'); process.exit(1); } this.intervalErrorChecked = true; } //Avoid dereferencing inside of function objects later //Must be performed on every execution var thisTimer = this; if(this.intervalTime > 0){ //Check and set constant t1 value. if(this.intervalT1 == null){ this.intervalT1 = process.hrtime(); } //Check for overflow. Every 8,000,000 seconds (92.6 days), this will overflow //and the reference time T1 will be re-acquired. This is the only case in which error will //propagate. if(this.intervalTime*this.intervalCount > 8000000000000000){ this.intervalT1 = process.hrtime(); this.intervalCount = 1; } //Get comparison time this.difArray = process.hrtime(this.intervalT1); this.difTime = (this.difArray[0] * 1000000000) + this.difArray[1]; //If updated time < expected time, continue //Otherwise, run task and update counter if(this.difTime < (this.intervalTime*this.intervalCount)){ //Can potentially defer to less accurate setTimeout if intervaltime > 25ms if(this.intervalTime > 25000000){ if(this.deferredInterval == false){ this.deferredInterval = true; var msDelay = (this.intervalTime - 25000000) / 1000000.0; this.deferredIntervalRef = setTimeout(function(){thisTimer.setInterval(task, args, interval, callback);}, msDelay); } else { this.deferredIntervalRef = null; this.intervalImmediateRef = setImmediate(function(){thisTimer.setInterval(task, args, interval, callback);}); } } else { this.intervalImmediateRef = setImmediate(function(){thisTimer.setInterval(task, args, interval, callback);}); } } else { this.intervalImmediateRef = null; if(this.logging){ console.log('nanotimer log: ' + 'cycle time at - ' + this.difTime); } if(args){ task.apply(null, args); } else { task(); } //Check if the intervalT1 is still not NULL. If it is, that means the task cleared the interval so it should not run again. if(this.intervalT1){ this.intervalCount++; this.deferredInterval = false; this.intervalImmediateRef = setImmediate(function(){thisTimer.setInterval(task, args, interval, callback);}); } } //If interval = 0, run as fast as possible. } else { //Check and set constant t1 value. if(this.intervalT1 == null){ this.intervalT1 = process.hrtime(); } if(args){ task.apply(null, args); } else { task(); } // This needs to be re-checked here incase calling task turned this off if(this.intervalT1){ this.intervalImmediateRef = setImmediate(function(){thisTimer.setInterval(task, args, interval, callback);}); } } }; NanoTimer.prototype.setTimeout = function(task, args, delay, callback){ //Task error handling if(!task){ console.log("A task function must be specified to setTimeout"); process.exit(1); } else { if(typeof(task) != "function"){ console.log("Task argument to setTimeout must be a function reference"); process.exit(1); } } //Delay error handling if(!delay){ console.log("A delay argument must be specified"); process.exit(1); } else { if(typeof(delay) != "string"){ console.log("Delay argument to setTimeout must be a string specified as an integer followed by 's' for seconds, 'm' for milli, 'u' for micro, and 'n' for nanoseconds. Ex. 2u"); process.exit(1); } } //This ref is used if deferred timeout is cleared, so the callback can still be accessed if(callback){ if(typeof(callback) != "function"){ console.log("Callback argument to setTimeout must be a function reference"); process.exit(1); } else { this.timeoutCallbackRef = callback; } } //Avoid dereferencing var thisTimer = this; if(this.timeoutTriggered){ this.timeoutTriggered = false; } var delayType = delay[delay.length-1]; if(delayType == 's'){ var delayTime = delay.slice(0, delay.length-1) * 1000000000; } else if(delayType == 'm'){ var delayTime = delay.slice(0, delay.length-1) * 1000000; } else if(delayType == 'u'){ var delayTime = delay.slice(0, delay.length-1) * 1000; } else if(delayType == 'n'){ var delayTime = delay.slice(0, delay.length-1); } else { console.log('Error with argument: ' + delay + ': Incorrect delay format. Format is an integer followed by "s" for seconds, "m" for milli, "u" for micro, and "n" for nanoseconds. Ex. 2u'); process.exit(1); } //Set marker if(this.timeOutT1 == null){ this.timeOutT1 = process.hrtime(); } var difArray = process.hrtime(this.timeOutT1); var difTime = (difArray[0] * 1000000000) + difArray[1]; if(difTime < delayTime){ //Can potentially defer to less accurate setTimeout if delayTime > 25ms if(delayTime > 25000000){ if(this.deferredTimeout == false){ this.deferredTimeout = true; var msDelay = (delayTime - 25000000) / 1000000.0; this.deferredTimeoutRef = setTimeout(function(){thisTimer.setTimeout(task, args, delay, callback);}, msDelay); } else { this.deferredTimeoutRef = null; this.timeoutImmediateRef = setImmediate(function(){thisTimer.setTimeout(task, args, delay, callback);}); } } else { this.timeoutImmediateRef = setImmediate(function(){thisTimer.setTimeout(task, args, delay, callback);}); } } else { this.timeoutTriggered = true; this.timeoutImmediateRef = null; this.timeOutT1 = null; this.deferredTimeout = false; if(this.logging == true){ console.log('nanotimer log: ' + 'actual wait - ' + difTime); } if(args){ task.apply(null, args); } else{ task(); } if(callback){ var data = {'waitTime':difTime}; callback(data); } } }; NanoTimer.prototype.clearInterval = function(){ if(this.deferredIntervalRef){ clearTimeout(this.deferredIntervalRef); this.deferredInterval = false; } if(this.intervalImmediateRef){ clearImmediate(this.intervalImmediateRef); } this.intervalT1 = null; this.intervalCount = 1; this.intervalErrorChecked = false; if(this.intervalCallbackRef){ this.intervalCallbackRef(); } }; NanoTimer.prototype.clearTimeout = function(){ // Only do something if this is not being called as a result // of the timeout triggering if(this.timeoutTriggered == false){ if(this.deferredTimeoutRef){ clearTimeout(this.deferredTimeoutRef); if(this.timeOutT1) { var difArray = process.hrtime(this.timeOutT1); var difTime = (difArray[0] * 1000000000) + difArray[1]; } this.deferredTimeout = false; } if(this.timeoutImmediateRef){ clearImmediate(this.timeoutImmediateRef); } this.timeOutT1 = null; if(this.timeoutCallbackRef){ var data = {'waitTime':difTime}; this.timeoutCallbackRef(data); } } }; NanoTimer.prototype.hasTimeout = function(){ return this.timeOutT1 != null; }; module.exports = NanoTimer; ================================================ FILE: package.json ================================================ { "name": "nanotimer", "main": "./lib/nanotimer.js", "description": "A much higher accuracy timer object that makes use of the node.js hrtime function call.", "version": "0.3.15", "authors": [ "Kevin Briggs (https://github.com/Krb686)" ], "keywords": [ "timer", "nanotimer", "nano", "nanoseconds", "micro", "microseconds", "stopwatch" ], "repository": { "type": "git", "url": "https://github.com/Krb686/nanotimer.git" }, "devDependencies": { "mocha": "^2.3.4", "should": "^7.1.1" }, "scripts": { "test": "mocha" }, "license": "ISC" } ================================================ FILE: test/test-nanotimer.js ================================================ var NanoTimer = require('../lib/nanotimer.js'); var should = require('should'); var timerA = new NanoTimer('log'); describe('nanoTimer', function(){ this.timeout(60 * 1000); //######## time function ######### describe('.time', function(){ //Test 1 - Synchronous Task Timing it('#1: synchronous, count to 1 million, 1000 samples', function(){ var times = []; var i = 0; var numSamples = 1000; //Simple count to 1 million task var syncTask = function(){ var count = 0; var i = 0; for(i=0;i<1000000;i++){ count++; }; }; //Test numSamples # of times for(i=0;i max){ max = times[i]; } if(times[i] < min){ min = times[i]; } } avg = avg/numSamples; console.log('\n\t\t - Average time: ' + avg + ' milliseconds'); console.log('\t\t - Max time: ' + max + ' milliseconds'); console.log('\t\t - Min time: ' + min + ' milliseconds'); }); //Test 2 - Asynchronous Task Timing it('#2: asynchronous, count to 1 million, 1000 samples', function(done){ var i = 0; var j = 0; var numSamples = 1000; var doneCount = 0; var times = []; //Count to 1000 asynchronously var asyncTask = function(callback){ if(i < 1000000){ setImmediate(function(){asyncTask(callback);}); } else { callback(); } i++; }; //Run 10 instances of async task. for(j=0;j max){ max = times[i]; } if(times[i] < min){ min = times[i]; } } avg = avg/numSamples; console.log('\n\t\t - Average time: ' + avg + ' seconds'); console.log('\t\t - Max time: ' + max + ' seconds'); console.log('\t\t - Min time: ' + min + ' seconds'); done(); } }); } }); it('#3: asnyc - make sure callback format is correct', function(done) { timerA.time(function methodReturningAfterApprox2000ms(callback) { setTimeout(callback, 2000); }, '', 'm', function resultCallback(timeTakenInMs) { timeTakenInMs.should.be.within(1900, 2100); console.log('\t\t - Time taken should be between 1900-2100 ms'); console.log('\t\t - Time taken: ' + timeTakenInMs); done(); }); }); }); //######## timeout function ######## describe('.setTimeout && clearTimeout', function(){ //Test 4 - sync task it('#4: sync, wait 0.1 seconds, 20 samples\n\n', function(done){ var i = 0; var j = 0; var numSamples = 20; var doneCount = 0; var errors = []; var minError = 1000000000; var maxError = 0; var avgError = 0; var task = function(){ var count = 0; for(i=0;i<1000000;i++){ count++; }; }; for(j=0;j= 100000000); waitedLongEnough.should.be.true; doneCount++; if(doneCount == numSamples){ for(i=0;i maxError){ maxError = errors[i]; } avgError += errors[i]; } avgError = avgError / numSamples; console.log('\t\t - Min. Error: ' + minError + '%'); console.log('\t\t - Max. Error: ' + maxError + '%'); console.log('\t\t - Avg. Error: ' + avgError + '%'); done(); } }); } }); //Test 5 - async task it('#5: setTimeout on async function with callback\n\n', function(done){ var asyncTask = function(callback, i){ if(!i){ var i = 0; } if(i < 1000){ setImmediate(function(){ i++; asyncTask(callback, i); }); } else { callback('got data'); } }; var runAsync = function(){ var msg = ''; asyncTask(function(data){ msg = data; msg.should.eql('got data'); }); }; timerA.setTimeout(runAsync, [], '1s', function(data) { var waitTime = data.waitTime; console.log('\t\t - Expected wait: 1 seconds'); console.log('\t\t - Actual wait: ' + waitTime/1000000000 + ' seconds'); console.log('\t\t - Error: ' + (((waitTime - 1000000000) / (1000000000)) * 100) + '%'); var waitedLongEnough = (waitTime >= 1000000000); waitedLongEnough.should.be.true; done(); }); }); //Test #6 - timeout with args passed it('#6 works with functions with args passed in\n\n', function(done){ var someObject = {}; someObject.number = 10; var taskWithArgs = function(object){ object.number = 5; }; timerA.setTimeout(taskWithArgs, [someObject], '1s', function(data){ var waitTime = data.waitTime; console.log('\t\t - Expected wait: 1 seconds'); console.log('\t\t - Actual wait: ' + waitTime/1000000000 + ' seconds'); console.log('\t\t - Error: ' + (((waitTime - 1000000000) / (1000000000)) * 100) + '%'); var waitedLongEnough = (waitTime >= 1000000000); waitedLongEnough.should.be.true; someObject.number.should.eql(5); done(); }); }); //Test #7 - clearTimeout works it('#7 clearTimeout before task is run - works\n\n', function(done){ var value = 0; var task = function(){ console.log('\t\t #6 task was run!'); value++; }; timerA.setTimeout(task, [], '1s', function(data){ var waitTime = data.waitTime; console.log('\t\t - Expected wait: 1 second'); console.log('\t\t - Actual wait: ' + waitTime/1000000000 + ' seconds'); var waitedShortEnough = (waitTime < 1000000000); waitedShortEnough.should.be.true; value.should.eql(0); done(); }); timerA.clearTimeout(); }); }); //######## setInterval function ######## describe('setInterval && clearInterval', function(){ //Test #8 - setInterval works it('#8 successfully works\n\n', function(done){ var task = function(){ console.log('\t\t - task was run!'); }; timerA.setInterval(task, [], '0.1s', function(){ done(); }); timerA.setTimeout(function(){ console.log('\t\t - clearing interval'); timerA.clearInterval(); }, [], '5s'); }); it('#9 setInterval with interval = 0: incrementing a variable as fast as possible.', function(done){ var i=0; var taskCount = 0; var task = function(){ i++; } var launchTask = function(){ console.log("Task is being launched!"); timerA.setInterval(task, [], '0s', function(){ console.log("Task count = " + taskCount); if(taskCount < 10){ console.log("relaunching"); taskCount++; console.log("i = " + i); i = 0; launchTask(); } else { console.log("Test #8 done!") done(); } }); console.log("T8 - setting timeout"); timerA.setTimeout(function(){ console.log('\t\t T8 - clearing interval'); timerA.clearInterval(); }, [], '0.2s'); } console.log("starting the initial task"); // Trigger the first launch launchTask(); }); it('#10 setInterval - clearing interval from within the task, non-zero timeout', function(done){ console.log("Starting test #9"); console.log("Clearing the interval from the task, zon-zero timeout"); var task = function(){ console.log("Running some task!"); var i = 0; while(i<100){ i++; } console.log("Clearing the interval"); timerA.clearInterval(); }; timerA.setInterval(task, [], '1s', function(){ console.log("Test #9 done!"); done(); }); }); it('#11 setInterval - clearing the interval from within the task, zero timeout', function(done){ console.log("Starting test #10"); console.log("Clearing the interval from the task, zero timeout"); var i=0; var task = function(){ if(i < 10){ console.log("i = " + i); i++; } else { timerA.clearInterval(); } }; timerA.setInterval(task, [], '0s', function(){ done(); }); }); }); });