'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = queue; var _baseIndexOf = require('lodash/_baseIndexOf'); var _baseIndexOf2 = _interopRequireDefault(_baseIndexOf); var _isArray = require('lodash/isArray'); var _isArray2 = _interopRequireDefault(_isArray); var _noop = require('lodash/noop'); var _noop2 = _interopRequireDefault(_noop); var _onlyOnce = require('./onlyOnce'); var _onlyOnce2 = _interopRequireDefault(_onlyOnce); var _setImmediate = require('./setImmediate'); var _setImmediate2 = _interopRequireDefault(_setImmediate); var _DoublyLinkedList = require('./DoublyLinkedList'); var _DoublyLinkedList2 = _interopRequireDefault(_DoublyLinkedList); var _wrapAsync = require('./wrapAsync'); var _wrapAsync2 = _interopRequireDefault(_wrapAsync); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function queue(worker, concurrency, payload) { if (concurrency == null) { concurrency = 1; } else if (concurrency === 0) { throw new Error('Concurrency must not be zero'); } var _worker = (0, _wrapAsync2.default)(worker); var numRunning = 0; var workersList = []; var processingScheduled = false; function _insert(data, insertAtFront, callback) { if (callback != null && typeof callback !== 'function') { throw new Error('task callback must be a function'); } q.started = true; if (!(0, _isArray2.default)(data)) { data = [data]; } if (data.length === 0 && q.idle()) { // call drain immediately if there are no tasks return (0, _setImmediate2.default)(function () { q.drain(); }); } for (var i = 0, l = data.length; i < l; i++) { var item = { data: data[i], callback: callback || _noop2.default }; if (insertAtFront) { q._tasks.unshift(item); } else { q._tasks.push(item); } } if (!processingScheduled) { processingScheduled = true; (0, _setImmediate2.default)(function () { processingScheduled = false; q.process(); }); } } function _next(tasks) { return function (err) { numRunning -= 1; for (var i = 0, l = tasks.length; i < l; i++) { var task = tasks[i]; var index = (0, _baseIndexOf2.default)(workersList, task, 0); if (index === 0) { workersList.shift(); } else if (index > 0) { workersList.splice(index, 1); } task.callback.apply(task, arguments); if (err != null) { q.error(err, task.data); } } if (numRunning <= q.concurrency - q.buffer) { q.unsaturated(); } if (q.idle()) { q.drain(); } q.process(); }; } var isProcessing = false; var q = { _tasks: new _DoublyLinkedList2.default(), concurrency: concurrency, payload: payload, saturated: _noop2.default, unsaturated: _noop2.default, buffer: concurrency / 4, empty: _noop2.default, drain: _noop2.default, error: _noop2.default, started: false, paused: false, push: function (data, callback) { _insert(data, false, callback); }, kill: function () { q.drain = _noop2.default; q._tasks.empty(); }, unshift: function (data, callback) { _insert(data, true, callback); }, remove: function (testFn) { q._tasks.remove(testFn); }, process: function () { // Avoid trying to start too many processing operations. This can occur // when callbacks resolve synchronously (#1267). if (isProcessing) { return; } isProcessing = true; while (!q.paused && numRunning < q.concurrency && q._tasks.length) { var tasks = [], data = []; var l = q._tasks.length; if (q.payload) l = Math.min(l, q.payload); for (var i = 0; i < l; i++) { var node = q._tasks.shift(); tasks.push(node); workersList.push(node); data.push(node.data); } numRunning += 1; if (q._tasks.length === 0) { q.empty(); } if (numRunning === q.concurrency) { q.saturated(); } var cb = (0, _onlyOnce2.default)(_next(tasks)); _worker(data, cb); } isProcessing = false; }, length: function () { return q._tasks.length; }, running: function () { return numRunning; }, workersList: function () { return workersList; }, idle: function () { return q._tasks.length + numRunning === 0; }, pause: function () { q.paused = true; }, resume: function () { if (q.paused === false) { return; } q.paused = false; (0, _setImmediate2.default)(q.process); } }; return q; } module.exports = exports['default'];