|
|
/** * Module dependencies. */
try { var EventEmitter = require('events').EventEmitter; if (!EventEmitter) throw new Error(); } catch (err) { var Emitter = require('emitter'); }
/** * Defer. */
var defer = typeof process !== 'undefined' && process && typeof process.nextTick === 'function' ? process.nextTick : function(fn){ setTimeout(fn); };
/** * Noop. */
function noop(){}
/** * Expose `Batch`. */
module.exports = Batch;
/** * Create a new Batch. */
function Batch() { if (!(this instanceof Batch)) return new Batch; this.fns = []; this.concurrency(Infinity); this.throws(true); for (var i = 0, len = arguments.length; i < len; ++i) { this.push(arguments[i]); } }
/** * Inherit from `EventEmitter.prototype`. */
if (EventEmitter) { Batch.prototype.__proto__ = EventEmitter.prototype; } else { Emitter(Batch.prototype); }
/** * Set concurrency to `n`. * * @param {Number} n * @return {Batch} * @api public */
Batch.prototype.concurrency = function(n){ this.n = n; return this; };
/** * Queue a function. * * @param {Function} fn * @return {Batch} * @api public */
Batch.prototype.push = function(fn){ this.fns.push(fn); return this; };
/** * Set wether Batch will or will not throw up. * * @param {Boolean} throws * @return {Batch} * @api public */ Batch.prototype.throws = function(throws) { this.e = !!throws; return this; };
/** * Execute all queued functions in parallel, * executing `cb(err, results)`. * * @param {Function} cb * @return {Batch} * @api public */
Batch.prototype.end = function(cb){ var self = this , total = this.fns.length , pending = total , results = [] , errors = [] , cb = cb || noop , fns = this.fns , max = this.n , throws = this.e , index = 0 , done;
// empty
if (!fns.length) return defer(function(){ cb(null, results); });
// process
function next() { var i = index++; var fn = fns[i]; if (!fn) return; var start = new Date;
try { fn(callback); } catch (err) { callback(err); }
function callback(err, res){ if (done) return; if (err && throws) return done = true, defer(function(){ cb(err); }); var complete = total - pending + 1; var end = new Date;
results[i] = res; errors[i] = err;
self.emit('progress', { index: i, value: res, error: err, pending: pending, total: total, complete: complete, percent: complete / total * 100 | 0, start: start, end: end, duration: end - start });
if (--pending) next(); else defer(function(){ if(!throws) cb(errors, results); else cb(null, results); }); } }
// concurrency
for (var i = 0; i < fns.length; i++) { if (i == max) break; next(); }
return this; };
|