Stackedit/js/async-runner.js

116 lines
2.8 KiB
JavaScript
Raw Normal View History

2013-03-30 11:56:17 +00:00
/**
2013-04-02 18:42:47 +00:00
* Used to run asynchronous tasks sequentially (ajax mainly)
2013-03-30 11:56:17 +00:00
* An asynchronous task must be created with:
2013-04-01 01:06:52 +00:00
* - a required run() function that may call success(), error() or retry()
2013-03-31 15:33:28 +00:00
* - an optional onSuccess() function
* - an optional onError() function
2013-04-01 01:06:52 +00:00
* - an optional timeout field (default is 30000)
2013-03-30 11:56:17 +00:00
*/
2013-04-14 13:24:29 +00:00
define(["underscore"], function() {
2013-04-02 18:42:47 +00:00
2013-03-30 11:56:17 +00:00
var asyncTaskRunner = {};
2013-04-10 18:14:59 +00:00
// Dependencies
var core = undefined;
2013-03-30 11:56:17 +00:00
var asyncTaskQueue = [];
var currentTask = undefined;
2013-04-01 01:06:52 +00:00
var currentTaskRunning = false;
2013-04-10 18:14:59 +00:00
var currentTaskStartTime = 0;
2013-03-30 11:56:17 +00:00
// Run the next task in the queue if any and no other is running
2013-04-10 18:14:59 +00:00
function runTask() {
2013-03-30 11:56:17 +00:00
// If there is a task currently running
if(currentTaskRunning === true) {
2013-03-30 11:56:17 +00:00
// If the current task takes too long
2013-04-01 01:06:52 +00:00
var timeout = currentTask.timeout || ASYNC_TASK_DEFAULT_TIMEOUT;
2013-04-02 18:42:47 +00:00
if(currentTaskStartTime + timeout < core.currentTime) {
2013-03-30 11:56:17 +00:00
currentTask.error();
}
return;
}
2013-03-31 15:33:28 +00:00
2013-04-01 01:06:52 +00:00
if(currentTask === undefined) {
// If no task in the queue
if(asyncTaskQueue.length === 0) {
2013-03-30 11:56:17 +00:00
return;
}
2013-04-01 01:06:52 +00:00
// Dequeue an enqueued task
currentTask = asyncTaskQueue.shift();
2013-04-02 18:42:47 +00:00
currentTaskStartTime = core.currentTime;
core.showWorkingIndicator(true);
2013-04-01 01:06:52 +00:00
// Set task attributes and functions
currentTask.finished = false;
currentTask.retryCounter = 0;
currentTask.success = function() {
runSafe(this.onSuccess);
};
2013-04-01 01:06:52 +00:00
currentTask.error = function() {
runSafe(this.onError);
2013-04-01 01:06:52 +00:00
};
currentTask.retry = function() {
if(this.finished === true) {
return;
}
if(currentTask.retryCounter === 5) {
this.error();
return;
}
// Implement an exponential backoff
2013-04-10 18:14:59 +00:00
var delay = Math.pow(2, currentTask.retryCounter++) * 1000;
2013-04-02 18:42:47 +00:00
currentTaskStartTime = core.currentTime + delay;
2013-04-01 01:06:52 +00:00
currentTaskRunning = false;
asyncTaskRunner.runTask();
};
}
// Run the task
2013-04-02 18:42:47 +00:00
if(currentTaskStartTime <= core.currentTime) {
2013-04-01 01:06:52 +00:00
currentTaskRunning = true;
currentTask.run();
}
2013-04-10 18:14:59 +00:00
}
asyncTaskRunner.runTask = function() {
2013-04-14 13:24:29 +00:00
// Use defer to avoid stack overflow
_.defer(runTask);
2013-03-30 11:56:17 +00:00
};
function runSafe(func) {
2013-04-07 15:22:13 +00:00
if(currentTask === undefined || currentTask.finished === true) {
return;
}
try {
if(func) {
func();
}
} finally {
currentTask.finished = true;
currentTask = undefined;
currentTaskRunning = false;
if(asyncTaskQueue.length === 0) {
2013-04-02 18:42:47 +00:00
core.showWorkingIndicator(false);
}
else {
asyncTaskRunner.runTask();
}
}
}
2013-04-10 18:14:59 +00:00
// Add a task into the queue
2013-03-30 11:56:17 +00:00
asyncTaskRunner.addTask = function(asyncTask) {
asyncTaskQueue.push(asyncTask);
2013-04-07 15:22:13 +00:00
asyncTaskRunner.runTask();
2013-03-30 11:56:17 +00:00
};
2013-04-10 18:14:59 +00:00
asyncTaskRunner.init = function(coreModule) {
core = coreModule;
};
2013-03-30 11:56:17 +00:00
return asyncTaskRunner;
2013-04-02 18:42:47 +00:00
});
2013-03-30 11:56:17 +00:00