diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..97f075d --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2011 Kilian Ciuffolo, me@nailik.org + +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. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e76b838 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# node-fnqueue ![project status](http://dl.dropbox.com/u/2208502/maintained.png) + +A powerful utility for function chaining (inspired by [async](https://github.com/caolan/async)). + +## Dependencies + +- nodejs v0.4.12+ + +## Installation and first run + + $ git clone git://github.com/kilian/node-fnqueue.git + +## Usage + +Parameters: + +- Object of functions +- Global callback +- Concurrency level (default is max possible) + +Each field of first parameter (Functions object) must be an Array / Function. + +If you pass an Array you are declaring a needed dependency with another function, otherwise you are passing a Function, then you are declaring a dependency less step. + +Each function with a dependency is called with the result of the depended function as parameter. + +The global callback is called on the first error, or at the end of all functions. The first parameter is the err (if provided) and the second one is a data object with the result of the chain. + +FnQueue magically resolves all dependencies and executes functions in the right order with the provided concurrency level. + + var FnQueue = require('node-fnqueue'); +or for a verbose mode: + + var FnQueue = require('node-fnqueue').verbose(); + +Example: + + new FnQueue({ + funnyStuff: ['processSomething', 'searchSomething', function(time, searchResults, callback){ + // do something silly + callback(null, 'ciao!'); + }], + searchSomething: function(callback){ + // do something with database + callback(err, results); + }, + update: ['searchSomething', function(searchResults, callback){ + // change values inside results and save to db + callback(err); // no needs to return values + }], + processSomething: ['searchSomething', function(searchResults, callback){ + var start = new Date().getTime(); + // write a file log + var elapsedTime = new Date().getTime() - start; + callback(err, elapsedTime); // logs write time; + }] + },function(err, data){ + + if(err) + throw err; + + console.log(data.searchSomething); // results + console.log(data.update); // undefined + console.log(data.processSomething); // elapsedTime + console.log(data.funnyStuff); // 'ciao!' + }, 1); + +## License + +_This software is released under the MIT license cited below_. + + Copyright (c) 2010 Kilian Ciuffolo, me@nailik.org. All Rights Reserved. + + 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. \ No newline at end of file diff --git a/lib/fnqueue.js b/lib/fnqueue.js new file mode 100644 index 0000000..14a558e --- /dev/null +++ b/lib/fnqueue.js @@ -0,0 +1,93 @@ +function FnQueue(tasks, callback, concurrecyLevel){ + this.tasks = tasks; + this.callback = callback; + this.results = {}; + this.concurrecyLevel = concurrecyLevel || 'auto'; + this.runningNb = 0; + this.callNextFunction(); +}; + +FnQueue.verbose = function(){ + FnQueue.prototype.isVerbose = false; + return FnQueue; +}; + +FnQueue.prototype.isVerbose = true; + +FnQueue.prototype.onTaskComplete = function(taskName, err, result){ + + this.runningNb--; + + if(err){ + this.callback && this.callback(err, this.results); + return; + } + + this.results[taskName] = result || null; + this.callNextFunction(); +}; + +FnQueue.prototype.callNextFunction = function(){ + + var dependencies, finish = true, args; + + for(var taskName in this.tasks){ + + if(this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel) + return; + + dependencies = this.tasks[taskName]; + finish = false; + + // no dependecies declared + if(dependencies instanceof Function){ + + this.isVerbose && console.log('FnQueue executing: ' + taskName); + + this.runningNb++; + delete this.tasks[taskName]; + dependencies(this.onTaskComplete.bind(this, taskName)); + + break; + } + + args = this.getDependencies(dependencies); + + if(args){ + + args.push(this.onTaskComplete.bind(this, taskName)); + + this.isVerbose && console.log('FnQueue executing: ' + taskName); + + this.runningNb++; + delete this.tasks[taskName]; + dependencies.pop().apply(null, args); + + if(this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel) + return; + } + } + + finish && !this.runningNb && this.callback && this.callback(null, this.results); +}; + +FnQueue.prototype.getDependencies = function(dependencies){ + + var args = []; + + for(var i = 0; i < dependencies.length-1; i++){ + + if(this.results[dependencies[i]] === undefined){ + return false; + } + + var arg = this.results[dependencies[i]]; + + if(arg !== undefined) + args.push(arg); + } + + return args; +}; + +module.exports = FnQueue; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..d5ee11a --- /dev/null +++ b/package.json @@ -0,0 +1,4 @@ +{ + "name" : "fnqueue", + "main" : "./lib/fnqueue.js" +} \ No newline at end of file