queue.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. 'use strict';
  2. var util = require('util');
  3. var events = require('events');
  4. var _ = require('lodash');
  5. var SubQueue = require('./subqueue');
  6. module.exports = Queue;
  7. /**
  8. * Queue constructor
  9. * @param {String[]} [subQueue] The order of the sub-queues. First one will be runned first.
  10. */
  11. function Queue( subQueues ) {
  12. subQueues = subQueues || [];
  13. subQueues.push('default');
  14. subQueues = _.uniq(subQueues);
  15. this.queueNames = subQueues;
  16. this.__queues__ = {};
  17. subQueues.forEach(function( name ) {
  18. this.__queues__[name] = new SubQueue();
  19. }.bind(this));
  20. }
  21. util.inherits( Queue, events.EventEmitter );
  22. /**
  23. * Add a task to a queue.
  24. * @param {String} [name='default'] The sub-queue to append the task
  25. * @param {Function} task
  26. * @param {Object} [opt] Options hash
  27. * @param {String} [opt.once] If a task with the same `once` value is inside the
  28. * queue, don't add this task.
  29. * @param {Boolean} [opt.run] If `run` is false, don't run the task.
  30. */
  31. Queue.prototype.add = function( name, task, opt ) {
  32. if ( typeof name !== 'string' ) {
  33. opt = task;
  34. task = name;
  35. name = 'default';
  36. }
  37. this.__queues__[name].push( task, opt );
  38. // don't run the tasks if `opt.run` is false
  39. if (opt && opt.run === false) return;
  40. setImmediate(this.run.bind(this));
  41. };
  42. /**
  43. * Start emptying the queues
  44. * Tasks are always run from the higher priority queue down to the lowest. After each
  45. * task complete, the process is re-runned from the first queue until a task is found.
  46. *
  47. * Tasks are passed a `callback` method which should be called once the task is over.
  48. */
  49. Queue.prototype.run = function() {
  50. if ( this.running ) return;
  51. this.running = true;
  52. this._exec(function() {
  53. this.running = false;
  54. if (_(this.__queues__).map('__queue__').flatten().value().length === 0) {
  55. this.emit('end');
  56. }
  57. }.bind(this));
  58. };
  59. Queue.prototype._exec = function( done ) {
  60. var pointer = -1;
  61. var names = Object.keys( this.__queues__ );
  62. var next = function next() {
  63. pointer++;
  64. if ( pointer >= names.length ) return done();
  65. this.__queues__[ names[pointer] ].run( next.bind(this), this._exec.bind(this, done) );
  66. }.bind(this);
  67. next();
  68. };