goog.provide("spv.RequestQueue");
/**
* This class keeps track of requests that need to be executed in order.
* The requests are often not idempotent and should be in a defined order to
* avoid surprising behaviors. DsClient and its derivatives usually prefixes
* state bound calls with 'session'; these methods should as a rule always use
* this request queue as a guard.
* @export
* @constructor
*/
spv.RequestQueue = function() {
/**
* @private
* @type {Array.<Function>}
*/
this._request_queue = [];
/**
* @private
* @type {Function}
*/
this._request_in_progress = null;
}
/**
* Enqueue a request to be executed in a synchronized fasion.
*
* @param {function(function(Function))} request
*/
spv.RequestQueue.prototype.push = function(request) {
this._request_queue.push(request);
if (this._request_in_progress) {
return;
}
this.next(null);
}
/**
* Session requests that require synchronization must use this function.
*
* @param {?Function=} currentRequest
*/
spv.RequestQueue.prototype.next = function(currentRequest) {
var queue = this;
if (this._request_in_progress
&& currentRequest != this._request_in_progress) {
throw new Error("Dequeue out of order.");
}
var next_request = this._request_queue.shift();
if (!next_request) {
this._request_in_progress = null;
return;
}
this._request_in_progress = next_request;
var execute = function() {
next_request(wrap);
}
setTimeout(execute , 0);
/**
* @param {?Function} callback
*/
function wrap(callback) {
return function() {
if(next_request.abort) return;
try {
callback.apply(null, arguments);
queue.next(next_request);
}
catch(err) {
queue.clear();
throw err;
}
}
};
};
/**
* Clears the queue and aborts in flight requests so that their callbacks
* are not triggered.
*/
spv.RequestQueue.prototype.clear = function() {
if(this._request_in_progress) {
this._request_in_progress.abort = true;
}
this._request_in_progress = null;
for(var i=0; i<this._request_queue; ++i) {
this._request_queue[i].abort = true;
}
this._request_queue.length = 0;
}