/** * 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; };