| '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']; |