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