155 lines
5.2 KiB
JavaScript
155 lines
5.2 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
var DEFAULT_MAX = 5;
|
||
|
/**
|
||
|
* Default checker which validates if a next task should begin.
|
||
|
* This can be overwritten to write own checks for example checking the amount
|
||
|
* of used ram and waiting till the ram is low enough for a next task.
|
||
|
*
|
||
|
* It should always resolve with a boolean, either `true` to start a next task
|
||
|
* or `false` to stop executing a new task.
|
||
|
*
|
||
|
* If this method rejects, the error will propagate to the caller
|
||
|
* @param status
|
||
|
* @param tasks
|
||
|
* @returns {Promise}
|
||
|
*/
|
||
|
var defaultNextTaskCheck = function (status, tasks) {
|
||
|
return new Promise(function (resolve, reject) {
|
||
|
resolve(status.amountStarted < tasks.length);
|
||
|
});
|
||
|
};
|
||
|
var DEFAULT_OPTIONS = {
|
||
|
maxInProgress: DEFAULT_MAX,
|
||
|
failFast: false,
|
||
|
nextCheck: defaultNextTaskCheck
|
||
|
};
|
||
|
/**
|
||
|
* Raw throttle function, which can return extra meta data.
|
||
|
* @param tasks required array of tasks to be executed
|
||
|
* @param options Options object
|
||
|
* @returns {Promise}
|
||
|
*/
|
||
|
function raw(tasks, options) {
|
||
|
return new Promise(function (resolve, reject) {
|
||
|
var myOptions = Object.assign({}, DEFAULT_OPTIONS, options);
|
||
|
var result = {
|
||
|
amountDone: 0,
|
||
|
amountStarted: 0,
|
||
|
amountResolved: 0,
|
||
|
amountRejected: 0,
|
||
|
amountNextCheckFalsey: 0,
|
||
|
rejectedIndexes: [],
|
||
|
resolvedIndexes: [],
|
||
|
nextCheckFalseyIndexes: [],
|
||
|
taskResults: []
|
||
|
};
|
||
|
if (tasks.length === 0) {
|
||
|
return resolve(result);
|
||
|
}
|
||
|
var failedFast = false;
|
||
|
var currentTaskIndex = 0;
|
||
|
var executeTask = function (index) {
|
||
|
result.amountStarted++;
|
||
|
if (typeof tasks[index] === 'function') {
|
||
|
tasks[index]().then(function (taskResult) {
|
||
|
result.taskResults[index] = taskResult;
|
||
|
result.resolvedIndexes.push(index);
|
||
|
result.amountResolved++;
|
||
|
taskDone();
|
||
|
}, function (error) {
|
||
|
result.taskResults[index] = error;
|
||
|
result.rejectedIndexes.push(index);
|
||
|
result.amountRejected++;
|
||
|
if (myOptions.failFast === true) {
|
||
|
failedFast = true;
|
||
|
return reject(result);
|
||
|
}
|
||
|
taskDone();
|
||
|
});
|
||
|
}
|
||
|
else {
|
||
|
failedFast = true;
|
||
|
return reject(new Error('tasks[' + index + ']: ' + tasks[index] + ', is supposed to be of type function'));
|
||
|
}
|
||
|
};
|
||
|
var taskDone = function () {
|
||
|
//make sure no more tasks are spawned when we failedFast
|
||
|
if (failedFast === true) {
|
||
|
return;
|
||
|
}
|
||
|
result.amountDone++;
|
||
|
if (typeof myOptions.progressCallback === 'function') {
|
||
|
myOptions.progressCallback(result);
|
||
|
}
|
||
|
if (result.amountDone === tasks.length) {
|
||
|
return resolve(result);
|
||
|
}
|
||
|
if (currentTaskIndex < tasks.length) {
|
||
|
nextTask(currentTaskIndex++);
|
||
|
}
|
||
|
};
|
||
|
var nextTask = function (index) {
|
||
|
//check if we can execute the next task
|
||
|
myOptions.nextCheck(result, tasks).then(function (canExecuteNextTask) {
|
||
|
if (canExecuteNextTask === true) {
|
||
|
//execute it
|
||
|
executeTask(index);
|
||
|
}
|
||
|
else {
|
||
|
result.amountNextCheckFalsey++;
|
||
|
result.nextCheckFalseyIndexes.push(index);
|
||
|
taskDone();
|
||
|
}
|
||
|
}, reject);
|
||
|
};
|
||
|
//spawn the first X task
|
||
|
for (var i = 0; i < Math.min(myOptions.maxInProgress, tasks.length); i++) {
|
||
|
nextTask(currentTaskIndex++);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
exports.raw = raw;
|
||
|
/**
|
||
|
* Executes the raw function, but only return the task array
|
||
|
* @param tasks
|
||
|
* @param options
|
||
|
* @returns {Promise}
|
||
|
*/
|
||
|
function executeRaw(tasks, options) {
|
||
|
return new Promise(function (resolve, reject) {
|
||
|
raw(tasks, options).then(function (result) {
|
||
|
resolve(result.taskResults);
|
||
|
}, function (error) {
|
||
|
if (error instanceof Error) {
|
||
|
reject(error);
|
||
|
}
|
||
|
else {
|
||
|
reject(error.taskResults[error.rejectedIndexes[0]]);
|
||
|
}
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
/**
|
||
|
* Simply run all the promises after each other, so in synchronous manner
|
||
|
* @param tasks required array of tasks to be executed
|
||
|
* @param options Options object
|
||
|
* @returns {Promise}
|
||
|
*/
|
||
|
function sync(tasks, options) {
|
||
|
var myOptions = Object.assign({}, { maxInProgress: 1, failFast: true }, options);
|
||
|
return executeRaw(tasks, myOptions);
|
||
|
}
|
||
|
exports.sync = sync;
|
||
|
/**
|
||
|
* Exposes the same behaviour as Promise.All(), but throttled!
|
||
|
* @param tasks required array of tasks to be executed
|
||
|
* @param options Options object
|
||
|
* @returns {Promise}
|
||
|
*/
|
||
|
function all(tasks, options) {
|
||
|
var myOptions = Object.assign({}, { failFast: true }, options);
|
||
|
return executeRaw(tasks, myOptions);
|
||
|
}
|
||
|
exports.all = all;
|
||
|
//# sourceMappingURL=throttle.js.map
|