| 'use strict'; |
| |
| 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; |