taskgroup
Advanced tools
Comparing version 3.1.2 to 3.2.0
@@ -1,11 +0,11 @@ | ||
// Generated by CoffeeScript 1.6.2 | ||
// Generated by CoffeeScript 1.6.3 | ||
var EventEmitter, Task, TaskGroup, ambi, | ||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, | ||
__hasProp = {}.hasOwnProperty, | ||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, | ||
__slice = [].slice; | ||
__slice = [].slice, | ||
__bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; | ||
ambi = require('ambi'); | ||
EventEmitter = require('eventemitter2').EventEmitter2; | ||
EventEmitter = require('events').EventEmitter; | ||
@@ -21,7 +21,11 @@ Task = (function(_super) { | ||
Task.prototype.completed = false; | ||
Task.prototype.parent = null; | ||
Task.prototype.taskDomain = null; | ||
Task.prototype.name = null; | ||
Task.prototype.fn = null; | ||
Task.prototype.method = null; | ||
@@ -31,13 +35,11 @@ Task.prototype.args = null; | ||
function Task() { | ||
var args, fn, name; | ||
var args, method, name; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
this.setConfig = __bind(this.setConfig, this); | ||
Task.__super__.constructor.apply(this, arguments); | ||
name = fn = null; | ||
name = method = null; | ||
if (args.length) { | ||
if (args.length === 2) { | ||
name = args[0], fn = args[1]; | ||
name = args[0], method = args[1]; | ||
} else if (args.length === 1) { | ||
fn = args[0]; | ||
method = args[0]; | ||
} | ||
@@ -47,3 +49,3 @@ } | ||
name: name, | ||
fn: fn | ||
method: method | ||
}); | ||
@@ -55,3 +57,2 @@ this; | ||
var key, value; | ||
if (opts == null) { | ||
@@ -68,35 +69,73 @@ opts = {}; | ||
Task.prototype.run = function() { | ||
var complete, | ||
_this = this; | ||
Task.prototype.reset = function() { | ||
this.completed = false; | ||
this.running = false; | ||
this.result = null; | ||
return this; | ||
}; | ||
complete = function() { | ||
var args; | ||
Task.prototype.uncaughtExceptionCallback = function() { | ||
var args, err; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
err = args[0]; | ||
if (!this.completed) { | ||
this.complete(args); | ||
} | ||
this.emit('error', err); | ||
return this; | ||
}; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
_this.running = false; | ||
_this.result = args; | ||
return _this.complete(); | ||
}; | ||
this.running = true; | ||
this.emit('run'); | ||
process.nextTick(function() { | ||
var args; | ||
Task.prototype.completionCallback = function() { | ||
var args, err; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
if (!this.completed) { | ||
this.complete(args); | ||
this.emit.apply(this, ['complete'].concat(__slice.call(this.result))); | ||
} else { | ||
err = new Error("A task's completion callback has fired when the task was already in a completed state, this is unexpected"); | ||
this.emit('error', err); | ||
} | ||
return this; | ||
}; | ||
args = (_this.args || []).concat([complete]); | ||
return ambi.apply(null, [_this.fn.bind(_this)].concat(__slice.call(args))); | ||
}); | ||
Task.prototype.destroy = function() { | ||
this.removeAllListeners(); | ||
return this; | ||
}; | ||
Task.prototype.complete = function() { | ||
var completed; | ||
Task.prototype.complete = function(result) { | ||
this.completed = true; | ||
this.running = false; | ||
this.result = result; | ||
return this; | ||
}; | ||
completed = (this.result != null) && this.running === false; | ||
if (completed) { | ||
this.emit.apply(this, ['complete'].concat(__slice.call(this.result))); | ||
Task.prototype.fire = function() { | ||
var args, | ||
_this = this; | ||
args = (this.args || []).concat([this.completionCallback.bind(this)]); | ||
if (this.taskDomain == null) { | ||
this.taskDomain = require('domain').create(); | ||
this.taskDomain.on('error', this.uncaughtExceptionCallback.bind(this)); | ||
} | ||
return completed; | ||
this.taskDomain.run(function() { | ||
return ambi.apply(null, [_this.method.bind(_this)].concat(__slice.call(args))); | ||
}); | ||
return this; | ||
}; | ||
Task.prototype.run = function() { | ||
var err; | ||
if (this.completed) { | ||
err = new Error("A task was about to run but it has already completed, this is unexpected"); | ||
this.emit('error', err); | ||
} else { | ||
this.reset(); | ||
this.running = true; | ||
this.emit('run'); | ||
process.nextTick(this.fire.bind(this)); | ||
} | ||
return this; | ||
}; | ||
return Task; | ||
@@ -123,5 +162,7 @@ | ||
TaskGroup.prototype.bubbleEvents = null; | ||
TaskGroup.prototype.name = null; | ||
TaskGroup.prototype.fn = null; | ||
TaskGroup.prototype.method = null; | ||
@@ -133,32 +174,23 @@ TaskGroup.prototype.concurrency = 1; | ||
function TaskGroup() { | ||
var args, fn, name, | ||
_this = this; | ||
var args, me, method, name; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
this.run = __bind(this.run, this); | ||
this.pause = __bind(this.pause, this); | ||
this.exit = __bind(this.exit, this); | ||
this.stop = __bind(this.stop, this); | ||
this.clear = __bind(this.clear, this); | ||
this.complete = __bind(this.complete, this); | ||
this.nextItem = __bind(this.nextItem, this); | ||
this.nextItems = __bind(this.nextItems, this); | ||
this.isReady = __bind(this.isReady, this); | ||
this.hasItems = __bind(this.hasItems, this); | ||
this.addGroup = __bind(this.addGroup, this); | ||
this.createGroup = __bind(this.createGroup, this); | ||
this.addTask = __bind(this.addTask, this); | ||
this.createTask = __bind(this.createTask, this); | ||
this.addItem = __bind(this.addItem, this); | ||
this.setConfig = __bind(this.setConfig, this); | ||
me = this; | ||
TaskGroup.__super__.constructor.apply(this, arguments); | ||
this.err = null; | ||
this.results = []; | ||
this.remaining = []; | ||
name = fn = null; | ||
if (this.results == null) { | ||
this.results = []; | ||
} | ||
if (this.remaining == null) { | ||
this.remaining = []; | ||
} | ||
if (this.bubbleEvents == null) { | ||
this.bubbleEvents = ['complete', 'run', 'error']; | ||
} | ||
name = method = null; | ||
if (args.length) { | ||
if (args.length === 2) { | ||
name = args[0], fn = args[1]; | ||
name = args[0], method = args[1]; | ||
} else if (args.length === 1) { | ||
fn = args[0]; | ||
method = args[0]; | ||
} | ||
@@ -168,36 +200,10 @@ } | ||
name: name, | ||
fn: fn | ||
method: method | ||
}); | ||
process.nextTick(function() { | ||
if (_this.fn) { | ||
args = [_this.addGroup, _this.addTask]; | ||
_this.addTask(_this.fn.bind(_this)).setConfig({ | ||
args: args, | ||
includeInResults: false | ||
}); | ||
if (!_this.parent) { | ||
return _this.run(); | ||
} | ||
} | ||
process.nextTick(this.fire.bind(this)); | ||
this.on('item.complete', this.itemCompletionCallback.bind(this)); | ||
this.on('item.error', function(item, err) { | ||
me.stop(); | ||
return me.emit('error', err); | ||
}); | ||
this.on('item.complete', function() { | ||
var args, item; | ||
item = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; | ||
if (item.includeInResults !== false) { | ||
_this.results.push(args); | ||
} | ||
if (args[0]) { | ||
_this.err = args[0]; | ||
} | ||
if (_this.running > 0) { | ||
--_this.running; | ||
} | ||
if (_this.paused) { | ||
return; | ||
} | ||
if (!_this.complete()) { | ||
return _this.nextItems(); | ||
} | ||
}); | ||
this; | ||
@@ -208,3 +214,2 @@ } | ||
var key, value; | ||
if (opts == null) { | ||
@@ -221,5 +226,40 @@ opts = {}; | ||
TaskGroup.prototype.fire = function() { | ||
var args; | ||
if (this.method) { | ||
args = [this.addGroup, this.addTask]; | ||
this.addTask(this.method.bind(this)).setConfig({ | ||
args: args, | ||
includeInResults: false | ||
}); | ||
if (!this.parent) { | ||
this.run(); | ||
} | ||
} | ||
return this; | ||
}; | ||
TaskGroup.prototype.itemCompletionCallback = function() { | ||
var args, item; | ||
item = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; | ||
if (item.includeInResults !== false) { | ||
this.results.push(args); | ||
} | ||
if (args[0]) { | ||
this.err = args[0]; | ||
} | ||
if (this.running > 0) { | ||
--this.running; | ||
} | ||
if (this.paused) { | ||
return; | ||
} | ||
if (!this.complete()) { | ||
this.nextItems(); | ||
} | ||
return this; | ||
}; | ||
TaskGroup.prototype.getTotals = function() { | ||
var completed, remaining, running, total; | ||
running = this.running; | ||
@@ -239,11 +279,11 @@ remaining = this.remaining.length; | ||
var me; | ||
me = this; | ||
item.onAny(function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return me.emit.apply(me, ["item." + this.event, item].concat(__slice.call(args))); | ||
this.bubbleEvents.forEach(function(bubbleEvent) { | ||
return item.on(bubbleEvent, function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return me.emit.apply(me, ["item." + bubbleEvent, item].concat(__slice.call(args))); | ||
}); | ||
}); | ||
this.emit('add', item); | ||
this.emit('item.add', item); | ||
this.remaining.push(item); | ||
@@ -258,3 +298,2 @@ if (!this.paused) { | ||
var args, task; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
@@ -271,3 +310,2 @@ task = (function(func, args, ctor) { | ||
var args, me, task; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
@@ -278,8 +316,10 @@ me = this; | ||
}); | ||
task.onAny(function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return me.emit.apply(me, ["task." + this.event, task].concat(__slice.call(args))); | ||
this.bubbleEvents.forEach(function(bubbleEvent) { | ||
return task.on(bubbleEvent, function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return me.emit.apply(me, ["task." + bubbleEvent, task].concat(__slice.call(args))); | ||
}); | ||
}); | ||
this.emit('task.add', task); | ||
return this.addItem(task); | ||
@@ -290,3 +330,2 @@ }; | ||
var args, group; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
@@ -303,3 +342,2 @@ group = (function(func, args, ctor) { | ||
var args, group, me; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
@@ -311,8 +349,10 @@ me = this; | ||
}); | ||
group.onAny(function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return me.emit.apply(me, ["group." + this.event, group].concat(__slice.call(args))); | ||
this.bubbleEvents.forEach(function(bubbleEvent) { | ||
return group.on(bubbleEvent, function() { | ||
var args; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
return me.emit.apply(me, ["group." + bubbleEvent, group].concat(__slice.call(args))); | ||
}); | ||
}); | ||
this.emit('group.add', group); | ||
return this.addItem(group); | ||
@@ -330,4 +370,3 @@ }; | ||
TaskGroup.prototype.nextItems = function() { | ||
var item, items; | ||
var item, items, result; | ||
items = []; | ||
@@ -342,7 +381,4 @@ while (true) { | ||
} | ||
if (items.length) { | ||
return items; | ||
} else { | ||
return false; | ||
} | ||
result = items.length ? items : false; | ||
return result; | ||
}; | ||
@@ -352,3 +388,2 @@ | ||
var nextItem; | ||
if (this.hasItems()) { | ||
@@ -367,3 +402,2 @@ if (this.isReady()) { | ||
var completed, empty, pause; | ||
pause = this.pauseOnError && this.err; | ||
@@ -384,6 +418,17 @@ empty = this.hasItems() === false && this.running === 0; | ||
TaskGroup.prototype.clear = function() { | ||
this.remaining.splice(0); | ||
var item, _i, _len, _ref; | ||
_ref = this.remaining.splice(0); | ||
for (_i = 0, _len = _ref.length; _i < _len; _i++) { | ||
item = _ref[_i]; | ||
item.destroy(); | ||
} | ||
return this; | ||
}; | ||
TaskGroup.prototype.destroy = function() { | ||
this.stop(); | ||
this.removeAllListeners(); | ||
return this; | ||
}; | ||
TaskGroup.prototype.stop = function() { | ||
@@ -411,11 +456,10 @@ this.pause(); | ||
TaskGroup.prototype.run = function() { | ||
var args, | ||
_this = this; | ||
var args, me; | ||
args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; | ||
me = this; | ||
this.paused = false; | ||
this.emit('run'); | ||
process.nextTick(function() { | ||
if (!_this.complete()) { | ||
return _this.nextItems(); | ||
if (!me.complete()) { | ||
return me.nextItems(); | ||
} | ||
@@ -422,0 +466,0 @@ }); |
{ | ||
"name": "taskgroup", | ||
"version": "3.1.2", | ||
"version": "3.2.0", | ||
"description": "Group together synchronous and asynchronous tasks and execute them with support for concurrency, naming, and nesting.", | ||
@@ -33,10 +33,9 @@ "homepage": "https://github.com/bevry/taskgroup", | ||
"dependencies": { | ||
"ambi": "~2.0.0", | ||
"eventemitter2": "~0.4.11" | ||
"ambi": "~2.1.0" | ||
}, | ||
"devDependencies": { | ||
"coffee-script": "~1.6.2", | ||
"joe": "~1.2.0", | ||
"joe": "~1.3.0", | ||
"joe-reporter-console": "~1.2.1", | ||
"chai": "~1.5.0" | ||
"chai": "~1.7.1" | ||
}, | ||
@@ -43,0 +42,0 @@ "directories": { |
@@ -5,2 +5,3 @@ # Task Group | ||
[![NPM version](https://badge.fury.io/js/taskgroup.png)](https://npmjs.org/package/taskgroup) | ||
[![Flattr this project](https://raw.github.com/balupton/flattr-buttons/master/badge-89x18.gif)](http://flattr.com/thing/344188/balupton-on-Flattr) | ||
@@ -95,3 +96,3 @@ Group together synchronous and asynchronous tasks and execute them with support for concurrency, naming, and nesting. | ||
``` javascript | ||
new require('taskgroup').TaskGroup() | ||
new (require('taskgroup')).TaskGroup() | ||
``` | ||
@@ -132,3 +133,3 @@ | ||
``` javascript | ||
new require('taskgroup').Task() | ||
new (require('taskgroup')).Task() | ||
``` | ||
@@ -151,2 +152,63 @@ | ||
## Comparison with [Async.js](https://github.com/caolan/async) | ||
The biggest advantage and difference of TaskGroup over async.js is that TaskGroup has one uniform API to rule them all, whereas with async.js I found that I was always having to keep referring to the async manual to try and figure out which is the right call for my use case then somehow wrap my head around the async.js way of doing things (which more often than not I couldn't), whereas with TaskGroup I never have that problem as it is one consistent API for all the different use cases. | ||
Let's take a look at what the most common async.js methods would look like in TaskGroup: | ||
``` javascript | ||
// ==================================== | ||
// Series | ||
// Async | ||
async.series([ | ||
function(){}, | ||
function(callback){callback();} | ||
], next); | ||
// TaskGroup | ||
new TaskGroup().once('complete', next) | ||
.addTask(function(){}) | ||
.addTask(function(callback){callback();}) | ||
.run(); | ||
// ==================================== | ||
// Parallel | ||
// Async | ||
async.parallel([ | ||
function(){}, | ||
function(callback){callback();} | ||
], next); | ||
// TaskGroup | ||
new TaskGroup().setConfig({concurrency:0}).once('complete', next) | ||
.addTask(function(){}) | ||
.addTask(function(callback){callback();}) | ||
.run(); | ||
// ==================================== | ||
// Map | ||
// Async | ||
async.map(['file1','file2','file3'], fs.stat, next); | ||
// TaskGroup | ||
var tasks = new TaskGroup().setConfig({concurrency:0}).once('complete', next); | ||
['file1','file2','file3'].forEach(function(file){ | ||
tasks.addTask(function(complete){ | ||
fs.stat(file,complete); | ||
}); | ||
}); | ||
tasks.run(); | ||
``` | ||
Another big advantage of TaskGroup over async.js is TaskGroup's ability to add tasks to the group once execution has already started - this is a common use case when creating an application that must perform it's actions serially, so using TaskGroup you can create a serial TaskGroup for the application, run it right away, then add the actions to the group as tasks. | ||
A final big advantage of TaskGroup over async.js is TaskGroup's ability to do nested groups, this allowed us to created the [Joe Testing Framework & Runner](https://github.com/bevry/joe) incredibly easily, and because of this functionality Joe will always know which test (task) is associated to which suite (task group), whereas test runners like mocha have to guess (they add the task to the last group, which may not always be the case! especially with dynamically created tests!). | ||
## History | ||
@@ -153,0 +215,0 @@ You can discover the history inside the [History.md](https://github.com/bevry/taskgroup/blob/master/History.md#files) file |
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
24130
1
445
219
+ Addedambi@2.1.6(transitive)
- Removedeventemitter2@~0.4.11
- Removedambi@2.0.0(transitive)
- Removedeventemitter2@0.4.14(transitive)
Updatedambi@~2.1.0