Socket
Socket
Sign inDemoInstall

fnqueue

Package Overview
Dependencies
0
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.5 to 2.0.0

69

lib/fnqueue.js

@@ -1,2 +0,2 @@

function FnQueue(tasks, callback, concurrecyLevel, stop){
function FnQueue(tasks, callback, concurrecyLevel, stop) {
this.tasks = tasks;

@@ -10,5 +10,5 @@ this.callback = callback;

!stop && this.callNextFunction();
};
}
FnQueue.verbose = function(){
FnQueue.verbose = function () {
FnQueue.prototype.isVerbose = true;

@@ -20,5 +20,5 @@ return FnQueue;

FnQueue.prototype.onTaskComplete = function(taskName, err, result){
FnQueue.prototype.onTaskComplete = function (taskName, err, result) {
if(this.gotError)
if (this.gotError)
return;

@@ -28,3 +28,3 @@

if(err){
if (err) {
this.gotError = true;

@@ -39,3 +39,3 @@ this.callback && this.callback(err, this.getResults());

FnQueue.prototype.getResults = function(){
FnQueue.prototype.getResults = function () {
var results = {};

@@ -47,38 +47,27 @@ for(var taskName in this.results)

FnQueue.prototype.callNextFunction = function(){
FnQueue.prototype.callNextFunction = function () {
var nextFunction, dependencies, finish = true, args;
for(var taskName in this.tasks){
for(var taskName in this.tasks) {
if(this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel)
return;
dependencies = this.tasks[taskName];
finish = false;
// no dependecies declared then we are passing the next function
if(dependencies instanceof Function){
if (this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel)
return;
nextFunction = dependencies;
this.isVerbose && console.log('FnQueue executing: ' + taskName);
nextFunction = this.tasks[taskName];
this.runningNb++;
delete this.tasks[taskName];
this.callSequence.push(taskName);
// postpone next function to next tick,
// will allow to close the current stack and keep the call order.
process.nextTick(nextFunction.bind(this, this.onTaskComplete.bind(this, taskName)));
continue;
if (nextFunction.length === 0) {
this.onTaskComplete(null, new Error('Invalid Function in chain: missing callback parameter'));
return;
}
dependencies = this.getFunctionArguments(nextFunction).slice(0, -1);
args = this.getDependencies(dependencies);
if(args){
if (args) {
args.push(this.onTaskComplete.bind(this, taskName));
this.isVerbose && console.log('FnQueue executing: ' + taskName);
this.isVerbose && console.log(' - FnQueue: executing: ' + taskName + '(' + dependencies.join(',') + ') { ... }');

@@ -88,6 +77,5 @@ this.runningNb++;

this.callSequence.push(taskName);
nextFunction = dependencies.pop();
nextFunction.apply(null, args);
if(this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel)
if (this.concurrecyLevel != 'auto' && this.runningNb >= this.concurrecyLevel)
return;

@@ -97,4 +85,3 @@ }

if(!finish && !nextFunction && !this.runningNb){
dependencies.pop();
if (!finish && this.runningNb === 0) {
this.onTaskComplete(null, new Error('Unresolvable dependencies: function "' + taskName + '" requires [' + dependencies.join(',') + ']'));

@@ -104,3 +91,3 @@ return;

if(finish && !this.runningNb && this.callback){
if (finish && !this.runningNb && this.callback) {
this.callback(null, this.getResults());

@@ -113,9 +100,13 @@ this.destroy();

FnQueue.prototype.getDependencies = function(dependencies){
FnQueue.prototype.getFunctionArguments = function (fn) {
return (/^function.+\(([a-z0-9\n\r\t ,]*)\)/i).exec(fn.toString())[1].trim().split(/[ ,\n\r\t]+/);
};
FnQueue.prototype.getDependencies = function (dependencies) {
var args = [];
for(var i = 0; i < dependencies.length-1; i++){
for(var i = 0; i < dependencies.length; i++) {
if(this.results[dependencies[i]] === undefined){
if (this.results[dependencies[i]] === undefined) {
return false;

@@ -126,3 +117,3 @@ }

if(arg !== undefined)
if (arg !== undefined)
args.push(arg.result);

@@ -134,3 +125,3 @@ }

FnQueue.prototype.destroy = function(){
FnQueue.prototype.destroy = function () {
delete this.results;

@@ -137,0 +128,0 @@ delete this.callback;

@@ -6,3 +6,3 @@ {

"description": "A powerful utility for function chaining",
"version": "1.0.5",
"version": "2.0.0",
"engines": {

@@ -19,4 +19,4 @@ "node": ">= v0.4.7"

"devDependencies": {
"vows": "0.5.x >=0.5.10"
"vows": "0.5.x >= 0.5.13"
}
}

@@ -5,10 +5,6 @@ # node-fnqueue ![project status](http://dl.dropbox.com/u/2208502/maintained.png)

## Dependencies
## Engine
- nodejs v0.4.12+
- nodejs v0.4.12+ (tested with v0.6.x)
## Installation as submodule
$ git clone git://github.com/kilian/node-fnqueue.git
## Installation with npm

@@ -18,17 +14,21 @@

## Usage
## Syntax
Parameters:
```javascript
new FnQueue(functionsList[, callback, concurrencyLevel]);
```
##Parameters
- Object of functions
- Global callback
- Concurrency level (default is max possible)
1. `functionsList` __(Object)__ a list of Functions. Each function can declare implicit dependencies as arguments and assume you provide a single callback as the last argument.
2. `callback` __(Function(err, data))__ the complete callback in the conventional form of `function (err, data){ ... }`
3. `concurrencyLevel` __(Number/String: defaults to 'auto')__ the concurrency level of the chain execution, can be `'auto'` or `N* = { 1, 2, ... }`
Each field of first parameter (Functions object) must be an Array / Function.
##Notes
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.
FnQueue runs a list of functions, each passing their results to the dependent function in the list. However, if any of the functions pass an error to the callback, the next function is not executed and the main callback is immediately called with the error.
Each function with a dependency is called with the result of the depended function as parameter.
Each dependency/argument must be named with the label of the dependent function in the `functionsList` (the first constructor argument).
Each function with a dependency will be called with the result of the dependent function as expected. __(YES this is a fucking cool introspection!)__
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.
The global callback is called once, on the first error or at the end of the execution. A data object will be provided with the indexed result of the functions.

@@ -38,3 +38,3 @@ FnQueue magically resolves all dependencies and executes functions in the right order with the provided concurrency level.

```javascript
var FnQueue = require('node-fnqueue');
var FnQueue = require('fnqueue');
```

@@ -44,3 +44,3 @@ or for a verbose mode:

```javascript
var FnQueue = require('node-fnqueue').verbose();
var FnQueue = require('fnqueue').verbose();
```

@@ -51,6 +51,8 @@ Example:

new FnQueue({
funnyStuff: ['processSomething', 'searchSomething', function(time, searchResults, callback){
// this will wait for 'processSomething' and 'searchSomething' and will be called with the respective results
funnyStuff: function(processSomething, searchSomething, callback){
// do something silly
callback(null, 'ciao!');
}],
},
// this will be called instantly
searchSomething: function(callback){

@@ -60,11 +62,13 @@ // do something with database

},
update: ['searchSomething', function(searchResults, callback){
// this will wait 'searchSomething'
update: function(searchSomething, callback){
// change values inside results and save to db
callback(err); // no needs to return values
}],
processSomething: ['searchSomething', function(searchResults, callback){
},
// this will wait 'searchSomething'
processSomething: function(searchSomething, callback){
var start = new Date().getTime();
// write a file log
// do something slow
var elapsedTime = new Date().getTime() - start;
callback(err, elapsedTime); // logs write time;
callback(err, elapsedTime);
}]

@@ -82,2 +86,21 @@ },function(err, data){

```
##Introspection profiling results
Profiling results are pretty good, Function.toString() took up __~2 seconds__ every __1 Million__ of executions.
Lines of code time (ms) Platform
---------------------------------------------------------------------------------------------------
800 1808ms OSX Lion 2.2 GHz Intel Core i7 / nodejs v6.0.1
## Test
Tests depends on http://vowsjs.org/ then
npm install -g vows
npm install
npm test
![tests](http://cl.ly/1R2q3h0G2c3a41303R1I/fnqueue_test_v2.png)
## License

@@ -84,0 +107,0 @@

@@ -5,9 +5,7 @@ var

FnQueue = require('../lib/fnqueue');
// macros = require('../macros');
function returnsArguments(askedResults, exptectedResults){
askedResults.push({});
return function(results){
function returnsArguments(askedResults, exptectedResults) {
return function (results) {
assert.deepEqual(FnQueue.prototype.getDependencies.apply(results, [askedResults]), exptectedResults);
}
};
}

@@ -18,3 +16,3 @@

topic: FnQueue.prototype,
'FnQueue.verbose should be false by default': function(prototype){
'FnQueue.verbose should be false by default': function (prototype) {
assert.isFalse(prototype.isVerbose);

@@ -24,2 +22,23 @@ }

}).addBatch({
'FnQueue.getFunctionArguments should success': {
'without spaces': function () {
assert.deepEqual(FnQueue.prototype.getFunctionArguments(function (foo,bar,callback) {}), ['foo', 'bar', 'callback']);
},
'with spaces': function () {
assert.deepEqual(FnQueue.prototype.getFunctionArguments(function ( foo , bar , callback ) { }), ['foo', 'bar', 'callback']);
},
'with newline': function () {
assert.deepEqual(FnQueue.prototype.getFunctionArguments(function (
foo,
bar,
callback
) {//foo bar
//foo bar
var a = 5;
for(var b = 0; b < 1000; b ++) { }
if (a == 5) { }
}), ['foo', 'bar', 'callback']);
}
}
}).addBatch({
'Given an object of results': {

@@ -40,3 +59,3 @@ topic: {

'FnQueue.getResults should return': {
'{ foo1: "foo1-result", bar1: "bar1-result", foo2: "foo2-result", bar2: "bar2-result" }': function(result){
'{ foo1: "foo1-result", bar1: "bar1-result", foo2: "foo2-result", bar2: "bar2-result" }': function (result) {
assert.deepEqual(FnQueue.prototype.getResults.apply(result), { foo1: "foo1-result", bar1: "bar1-result", foo2: "foo2-result", bar2: "bar2-result" });

@@ -54,3 +73,3 @@ }

'FnQueue.getResults should return': {
'{}': function(result){
'{}': function (result) {
assert.deepEqual(FnQueue.prototype.getResults.apply(result), {});

@@ -62,3 +81,3 @@ }

topic: { results: {}, callback: {}, tasks: {} },
'should delete results, callback and tasks properties': function(obj){
'should delete results, callback and tasks properties': function (obj) {
FnQueue.prototype.destroy.apply(obj);

@@ -69,14 +88,14 @@ assert.isEmpty(obj);

'FnQueue with an example queue of functions': {
topic: function(){
topic: function () {
new FnQueue({
fn1: function(callback){
fn1: function (callback) {
setTimeout(callback.bind(null, null, 'fn1'), 500);
},
fn2: function(callback){
fn2: function (callback) {
setTimeout(callback.bind(null, null, 'fn2'), 500);
},
fn3: function(callback){
fn3: function (callback) {
setTimeout(callback.bind(null, null, undefined), 500);
},
fn4: function(callback){
fn4: function (callback) {
setTimeout(callback.bind(null, null, false), 500);

@@ -86,9 +105,9 @@ }

},
'should not return error': function(err, data){
'should not return error': function (err, data) {
assert.isNull(err);
},
'data should be an Object': function(err, data){
'data should be an Object': function (err, data) {
assert.isObject(data);
},
'data should contains all the queue results': function(err, data){
'data should contains all the queue results': function (err, data) {
assert.deepEqual(data,{

@@ -103,14 +122,14 @@ fn1: 'fn1',

'FnQueue with some error throwing function': {
topic: function(){
topic: function () {
new FnQueue({
fn1: function(callback){
fn1: function (callback) {
setTimeout(callback.bind(null, null, 'fn1'), 200);
},
fn2: function(callback){
fn2: function (callback) {
setTimeout(callback.bind(null, new Error('This is thrown by fn2'), 'fn2'), 300);
},
fn3: function(callback){
fn3: function (callback) {
setTimeout(callback.bind(null, new Error('This is thrown by fn3'), undefined), 200);
},
fn4: function(callback){
fn4: function (callback) {
setTimeout(callback.bind(null, null, false), 200);

@@ -120,25 +139,26 @@ }

},
'should call the main callback with an error': function(err, data){
'should call the main callback with an error': function (err, data) {
assert.isNotNull(err);
},
'error message should be "This is thrown by fn3"': function(err, data){
'error message should be "This is thrown by fn3"': function (err, data) {
assert.equal(err.message, 'This is thrown by fn3');
},
'data should contains partial results': function(err, data){
'data should contains partial results': function (err, data) {
assert.deepEqual(data, { fn1: 'fn1' });
}
},
'FnQueue with some dependencies': {
topic: function(){
var fnQueue = new FnQueue({
fn1: ['fn2', 'fn4', 'fn3', function(fn2, fn4, fn3, callback){
}
}).addBatch({
'FnQueue with unresolvable dependencies': {
topic: function () {
new FnQueue({
fn1: function (fn2, fn4, fn3, callback) {
setTimeout(callback.bind(null, null, 'fn1'), 100);
}],
fn2: ['fn4', function(fn4, callback){
},
fn2: function (fn4, callback) {
setTimeout(callback.bind(null, null, 'fn2'), 100);
}],
fn3: ['fn2', function(fn2, callback){
},
fn3: function (fn2, fn1, callback) {
setTimeout(callback.bind(null, null, undefined), 100);
}],
fn4: function(callback){
},
fn4: function (callback) {
setTimeout(callback.bind(null, null, false), 100);

@@ -148,19 +168,26 @@ }

},
'should follow dependecies constrains in call sequence': function(err, data){
assert.deepEqual(this.callSequence, ['fn4', 'fn2', 'fn3', 'fn1']);
'should call the main callback with an error': function (err, data) {
assert.isNotNull(err);
},
'error should match the "Unresolvable dependencies..." messgae': function (err, data) {
assert.match(err.message, /^Unresolvable dependencies/);
},
'data should contain partial results': function (err, data) {
assert.deepEqual(data, { fn4: false, fn2: 'fn2' });
}
},
'FnQueue with unresolvable dependencies': {
topic: function(){
var fnQueue = new FnQueue({
fn1: ['fn2', 'fn4', 'fn3', function(fn2, fn4, fn3, callback){
}
}).addBatch({
'FnQueue with some dependencies': {
topic: function () {
new FnQueue({
fn1: function (fn2, fn4, fn3, callback) {
setTimeout(callback.bind(null, null, 'fn1'), 100);
}],
fn2: ['fn4', function(fn4, callback){
},
fn2: function (fn4, callback) {
setTimeout(callback.bind(null, null, 'fn2'), 100);
}],
fn3: ['fn2', 'fn1', function(fn2, callback){
},
fn3: function (fn2, callback) {
setTimeout(callback.bind(null, null, undefined), 100);
}],
fn4: function(callback){
},
fn4: function (callback) {
setTimeout(callback.bind(null, null, false), 100);

@@ -170,10 +197,4 @@ }

},
'should call the main callback with an error': function(err, data){
assert.isNotNull(err);
},
'error should match the "Unresolvable dependencies..." messgae': function(err, data){
assert.match(err.message, /^Unresolvable dependencies/);
},
'data should contain partial results': function(err, data){
assert.deepEqual(data, { fn4: false, fn2: 'fn2' });
'should follow dependecies constrains in call sequence': function (err, data) {
assert.deepEqual(this.callSequence, ['fn4', 'fn2', 'fn3', 'fn1']);
}

@@ -183,32 +204,32 @@ }

'FnQueue with an example queue of functions and a concurrency level of 2': {
topic: function(){
topic: function () {
var fnQueue = new FnQueue({
fn1: function(callback){
fn1: function (callback) {
setTimeout(getCallback(2, callback), 200);
},
fn2: ['fn9', function(f9, callback){
fn2: function (fn9, callback) {
setTimeout(getCallback(null, callback), 200);
}],
fn3: ['fn9', 'fn8', function(f9, f8, callback){
},
fn3: function (fn9, fn8, callback) {
setTimeout(getCallback(null, callback), 200);
}],
fn4: function(callback){
},
fn4: function (callback) {
setTimeout(getCallback(3, callback), 200);
},
fn5: function(callback){
fn5: function (callback) {
setTimeout(getCallback(null, callback), 200);
},
fn6: function(callback){
fn6: function (callback) {
setTimeout(getCallback(null, callback), 200);
},
fn7: function(callback){
fn7: function (callback) {
setTimeout(getCallback(1, callback), 200);
},
fn8: function(callback){
fn8: function (callback) {
setTimeout(getCallback(2, callback), 200);
},
fn9: ['fn7', 'fn8', function(fn7, fn8, callback){
fn9: function (fn7, fn8, callback) {
setTimeout(getCallback(null, callback), 200);
}]
}
}, this.callback, 1, true);

@@ -218,4 +239,4 @@

function getCallback(concurrecyLevel, callback){
return function(){
function getCallback(concurrecyLevel, callback) {
return function () {
concurrecyLevel && (fnQueue.concurrecyLevel = concurrecyLevel);

@@ -229,6 +250,6 @@ fnQueue.concurrencySequence.push(fnQueue.runningNb);

},
'should not return error': function(err, data){
'should not return error': function (err, data) {
assert.isNull(err);
},
'max concurrency should follow the expected concurrency sequence': function(err, data){
'max concurrency should follow the expected concurrency sequence': function (err, data) {
assert.deepEqual(this.concurrencySequence, [ 1, 2, 3, 3, 2, 1, 1, 2, 1 ]);

@@ -235,0 +256,0 @@ },

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc