/** * Module Dependencies */ var enqueue = require('enqueue'); var wrap = require('wrap-fn'); var once = require('once'); var noop = function(){}; var slice = [].slice; /** * Export `Batch` */ module.exports = Batch; /** * Initialize `Batch` * * @param {Function or Array or Batch} fn (optional) */ function Batch(fn) { if (!(this instanceof Batch)) return new Batch(fn); this.n = Infinity; this.throws(true); this.length = 0; this.fns = []; if (fn) this.push(fn); } /** * Set concurrency to `n`. * * @param {Number} n * @return {Batch} * @api public */ Batch.prototype.concurrency = function(n){ this.n = n; return this; }; /** * Set whether Batch will or will not throw up. * * @param {Boolean} throws * @return {Batch} * @api public */ Batch.prototype.throws = function(throws) { this.e = !!throws; return this; }; /** * Push a new function * * @param {Function|Generator} fn * @return {Batch} * @api public */ Batch.prototype.push = function (fn) { if (fn instanceof Batch) { return this.use(fn.fns); } if (fn instanceof Array) { for (var i = 0, f; f = fn[i++];) this.use(f); return this; } this.fns.push(fn); this.length = this.fns.length; return this; }; /** * Execute all queued functions in parallel, * executing `cb(err, results)`. * * @param {Mixed, ...} args * @param {Functio} fn (optional) * @return {Batch} * @api public */ Batch.prototype.end = function() { var args = slice.call(arguments); var last = args[args.length - 1]; var done = 'function' == typeof last && last; var len = this.length; var throws = this.e; var fns = this.fns; var pending = len; var results = []; var errors = []; var ctx = this; // update args var args = done ? slice.call(arguments, 0, arguments.length - 1) : slice.call(arguments); // only call done once done = once(done || noop); // empty if (!len) return done(null, results); // process function next(i) { return function(err, res) { if (err && throws) return done(err); results[i] = res; errors[i] = err; if (--pending) return; else if (!throws) done(errors, results); else done(null, results); } } // queue calls with `n` concurrency var call = enqueue(function(fn, i) { wrap(fn, next(i)).apply(ctx, args); }, this.n); // call the fns in parallel for (var i = 0, fn; fn = fns[i]; i++) call(fn, i); return this; };