Skip to content

Instantly share code, notes, and snippets.

@ischenkodv
Created February 28, 2015 20:17
Show Gist options
  • Save ischenkodv/e16338f72ae980ac57ed to your computer and use it in GitHub Desktop.
Save ischenkodv/e16338f72ae980ac57ed to your computer and use it in GitHub Desktop.
Asynchronous queue implementation. Functions could be added to queue and executed one by one immediately, or with intervals or in the next frame (using requestAnimationFrame).
;(function(window) {
'use strict';
/**
* AsyncQueue allows you to create a queue of function to be executed via
* setTimout that guaranteed to run in order. This can enable to run
* process-intensive operations without locking up UI.
*
* @constructor
* @param {Object} options Configuration options:
* context - Context in which to execute callbacks.
* timeout - Timeout to schedule callback execution.
* onComplete - Function to execute when queue is finished.
*/
function AsyncQueue(options) {
var ctx = this, key;
ctx._q = [];
ctx.options = {
context: window,
timeout: 1
};
options = options || {};
for (key in options) {
ctx.options[key] = options[key];
}
}
AsyncQueue.prototype = {
constructor: AsyncQueue,
/**
* Shows if there are currently running task.
* @private
* @type {Boolean}
*/
_running: false,
/**
* Schedule task on specified timeout.
* @private
* @param {Object} callback Task to execute.
* @param {Boolean} isFrame Execute task using request animation frame.
*/
_schedule: function(callback, isFrame) {
var ctx = this, fn;
ctx._scheduledCallback = callback;
fn = function() {
ctx._execute(ctx._scheduledCallback);
if (ctx._raf) {
ctx._raf = false;
}
ctx.run();
};
if (isFrame) {
ctx._raf = window.nextFrame(fn);
} else {
ctx._running = window.setTimeout(fn, callback.timeout);
}
},
/**
* Executes callback.
* @private
* @param {Object} callback
*/
_execute: function(callback) {
callback.fn.apply(callback.context, callback.args || []);
this._running = false;
},
/**
* Checks if any task is currently running.
* @return {boolean}
*/
isRunning: function() {
return this._running > 0 || this._raf > 0;
},
/**
* Add callback to the queue.
* @param {function|Object} callback
*/
add: function(callback) {
var ctx = this,
options = ctx.options;
if (typeof callback == 'function') {
ctx._q.push({
fn: callback,
context: options.context,
timeout: options.timeout
});
} else {
if (!callback.hasOwnProperty('timeout')) {
callback.timeout = options.timeout;
}
if (!callback.hasOwnProperty('context')) {
callback.context = options.context;
}
ctx._q.push(callback);
}
},
/**
* Stop queue execution.
*/
stop: function() {
var ctx = this;
if (ctx._running) {
window.clearTimeout(ctx._running);
ctx._scheduledCallback = null;
}
if (ctx._raf) {
window.cancelFrame(ctx._raf);
}
ctx._q = [];
ctx._raf = ctx._running = false;
},
/**
* Pause queue execution.
*/
pause: function() {
var ctx = this;
if (ctx._running) {
window.clearTimeout(ctx._running);
if (ctx._scheduledCallback) {
ctx._q.unshift(ctx._scheduledCallback);
}
} else if (ctx._raf) {
window.cancelFrame(ctx._raf);
if (ctx._scheduledCallback) {
ctx._q.unshift(ctx._scheduledCallback);
}
}
ctx._raf = ctx._running = false;
},
/**
* Returns the number of callbacks in the queue.
* @return {Number}
*/
size: function() {
return this._q.length;
},
/**
* Returns next queued function.
* @return {Object} Config object.
*/
next: function() {
return this._q.length > 0 ? this._q.shift() : false;
},
/**
* Runs queue. All callbacks will be executed in order unless pause() or
* stop() is called. When queue execution is complete the onComplete function
* will be called if it is defined.
*/
run: function() {
var ctx = this,
callback = ctx.next();
if (callback) {
if (callback.timeout > -1) {
ctx._schedule(callback);
} else if (callback.timeout == 'frame') {
ctx._schedule(callback, true);
} else {
ctx._execute(callback);
ctx.run();
return;
}
}
if (!ctx.isRunning() && ctx.size() === 0 && typeof ctx.options.onComplete === 'function') {
ctx.options.onComplete();
}
}
};
window.AsyncQueue = AsyncQueue;
})(window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment