You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							173 lines
						
					
					
						
							2.9 KiB
						
					
					
				
			
		
		
	
	
							173 lines
						
					
					
						
							2.9 KiB
						
					
					
				/** | 
						|
 * 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; | 
						|
};
 | 
						|
 |