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