115 lines
2.8 KiB
JavaScript
115 lines
2.8 KiB
JavaScript
/**
|
|
* Used to run asynchronous tasks sequentially (ajax mainly)
|
|
* An asynchronous task must be created with:
|
|
* - a required run() function that may call success(), error() or retry()
|
|
* - an optional onSuccess() function
|
|
* - an optional onError() function
|
|
* - an optional timeout field (default is 30000)
|
|
*/
|
|
define(["core"], function(core) {
|
|
|
|
var asyncTaskRunner = {};
|
|
|
|
var asyncTaskQueue = [];
|
|
var currentTask = undefined;
|
|
var currentTaskRunning = false;
|
|
var currentTaskStartTime = core.currentTime;
|
|
|
|
// Run the next task in the queue if any and no other is running
|
|
asyncTaskRunner.runTask = function() {
|
|
|
|
// If there is a task currently running
|
|
if(currentTaskRunning === true) {
|
|
// If the current task takes too long
|
|
var timeout = currentTask.timeout || ASYNC_TASK_DEFAULT_TIMEOUT;
|
|
if(currentTaskStartTime + timeout < core.currentTime) {
|
|
currentTask.error();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(currentTask === undefined) {
|
|
// If no task in the queue
|
|
if(asyncTaskQueue.length === 0) {
|
|
return;
|
|
}
|
|
|
|
// Dequeue an enqueued task
|
|
currentTask = asyncTaskQueue.shift();
|
|
currentTaskStartTime = core.currentTime;
|
|
core.showWorkingIndicator(true);
|
|
|
|
// Set task attributes and functions
|
|
currentTask.finished = false;
|
|
currentTask.retryCounter = 0;
|
|
currentTask.finish = function() {
|
|
this.finished = true;
|
|
currentTask = undefined;
|
|
currentTaskRunning = false;
|
|
if(asyncTaskQueue.length === 0) {
|
|
core.showWorkingIndicator(false);
|
|
}
|
|
else {
|
|
asyncTaskRunner.runTask();
|
|
}
|
|
};
|
|
currentTask.success = function() {
|
|
runSafe(this.onSuccess);
|
|
};
|
|
currentTask.error = function() {
|
|
runSafe(this.onError);
|
|
};
|
|
currentTask.retry = function() {
|
|
if(this.finished === true) {
|
|
return;
|
|
}
|
|
if(currentTask.retryCounter === 5) {
|
|
this.error();
|
|
return;
|
|
}
|
|
// Implement an exponential backoff
|
|
var delay = (Math.pow(2, currentTask.retryCounter++) + Math.random()) * 1000;
|
|
console.log(delay);
|
|
currentTaskStartTime = core.currentTime + delay;
|
|
currentTaskRunning = false;
|
|
asyncTaskRunner.runTask();
|
|
};
|
|
}
|
|
|
|
// Run the task
|
|
if(currentTaskStartTime <= core.currentTime) {
|
|
currentTaskRunning = true;
|
|
currentTask.run();
|
|
}
|
|
};
|
|
|
|
function runSafe(func) {
|
|
if(currentTask.finished === true) {
|
|
return;
|
|
}
|
|
try {
|
|
if(func) {
|
|
func();
|
|
}
|
|
} finally {
|
|
currentTask.finished = true;
|
|
currentTask = undefined;
|
|
currentTaskRunning = false;
|
|
if(asyncTaskQueue.length === 0) {
|
|
core.showWorkingIndicator(false);
|
|
}
|
|
else {
|
|
asyncTaskRunner.runTask();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add a task in the queue
|
|
asyncTaskRunner.addTask = function(asyncTask) {
|
|
asyncTaskQueue.push(asyncTask);
|
|
};
|
|
|
|
return asyncTaskRunner;
|
|
});
|
|
|