; | |
function Queue(options) { | |
if (!(this instanceof Queue)) { | |
return new Queue(options); | |
} | |
options = options || {}; | |
this.concurrency = options.concurrency || Infinity; | |
this.pending = 0; | |
this.jobs = []; | |
this.cbs = []; | |
this._done = done.bind(this); | |
} | |
var arrayAddMethods = [ | |
'push', | |
'unshift', | |
'splice' | |
]; | |
arrayAddMethods.forEach(function(method) { | |
Queue.prototype[method] = function() { | |
var methodResult = Array.prototype[method].apply(this.jobs, arguments); | |
this._run(); | |
return methodResult; | |
}; | |
}); | |
Object.defineProperty(Queue.prototype, 'length', { | |
get: function() { | |
return this.pending + this.jobs.length; | |
} | |
}); | |
Queue.prototype._run = function() { | |
if (this.pending === this.concurrency) { | |
return; | |
} | |
if (this.jobs.length) { | |
var job = this.jobs.shift(); | |
this.pending++; | |
job(this._done); | |
this._run(); | |
} | |
if (this.pending === 0) { | |
while (this.cbs.length !== 0) { | |
var cb = this.cbs.pop(); | |
process.nextTick(cb); | |
} | |
} | |
}; | |
Queue.prototype.onDone = function(cb) { | |
if (typeof cb === 'function') { | |
this.cbs.push(cb); | |
this._run(); | |
} | |
}; | |
function done() { | |
this.pending--; | |
this._run(); | |
} | |
module.exports = Queue; | |