commit/galaxy-central: carlfeberhard: JS utils: add ajax queue and named ajax queue to allow processing async calls in order and/or prevent duplicate async calls
1 new commit in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/bd2561df7d11/ Changeset: bd2561df7d11 User: carlfeberhard Date: 2014-03-04 18:33:51 Summary: JS utils: add ajax queue and named ajax queue to allow processing async calls in order and/or prevent duplicate async calls Affected #: 2 files diff -r afac236cffd149aaa68dcf08f73903e109d14e33 -r bd2561df7d11308bd717cadd0158d26fbcf7e4dc static/scripts/packed/utils/ajax-queue.js --- /dev/null +++ b/static/scripts/packed/utils/ajax-queue.js @@ -0,0 +1,1 @@ +define([],function(){function k(m){var l=this;l.deferred=jQuery.Deferred();l.queue=[];l.responses=[];l.numToProcess=0;l.running=false;l.init(m||[]);l.start();return l}k.prototype.init=function i(m){var l=this;m.forEach(function(n){l.add(n)})};k.prototype.add=function j(n){var l=this,m=this.queue.length;this.numToProcess+=1;this.queue.push(function(){var o=n();o.done(function(p){l.deferred.notify({curr:m,total:l.numToProcess,response:p})});o.always(function(p){l.responses.push(p);if(l.queue.length){l.queue.shift()()}else{l.stop()}})})};k.prototype.start=function b(){if(this.queue.length){this.running=true;this.queue.shift()()}};k.prototype.stop=function h(l,m){this.running=false;this.queue=[];if(l){this.deferred.reject(m)}else{this.deferred.resolve(this.responses)}return this};k.prototype.done=function f(l){return this.deferred.done(l)};k.prototype.fail=function d(l){return this.deferred.fail(l)};k.prototype.always=function e(l){return this.deferred.always(l)};k.prototype.progress=function a(l){return this.deferred.progress(l)};k.create=function g(l){return new AjaxQeueue(l).deferred};function c(m){var l=this;l.names={};k.call(this,m);return l}c.prototype=new k();c.prototype.constructor=c;c.prototype.add=function j(l){if(!(l.hasOwnProperty("name")&&l.hasOwnProperty("fn"))){throw new Error('NamedAjaxQueue.add requires an object with both "name" and "fn": '+JSON.stringify(l))}if(this.names.hasOwnProperty(l.name)){return}this.names[l.name]=true;k.prototype.add.call(this,l.fn)};c.create=function g(l){return new c(l).deferred};return{AjaxQueue:k,NamedAjaxQueue:c}}); \ No newline at end of file diff -r afac236cffd149aaa68dcf08f73903e109d14e33 -r bd2561df7d11308bd717cadd0158d26fbcf7e4dc static/scripts/utils/ajax-queue.js --- /dev/null +++ b/static/scripts/utils/ajax-queue.js @@ -0,0 +1,165 @@ +define([ +], function(){ +//ASSUMES: jquery +//============================================================================= +/** @class AjaxQueue + * Class that allows queueing functions that return jQuery promises (such + * as ajax calls). Each function waits for the previous to complete before + * being called + * + * @constructor accepts a list of functions and automatically begins + * processing them + */ +function AjaxQueue( initialFunctions ){ + //TODO: possibly rename to DeferredQueue + var self = this; + /** the main deferred for the entire queue - note: also sends notifications of progress */ + self.deferred = jQuery.Deferred(); + /** the queue array of functions */ + self.queue = []; + /** cache the response from each deferred call - error or success */ + self.responses = []; + /** total number of fn's to process */ + self.numToProcess = 0; + /** is the queue processing/waiting for any calls to return? */ + self.running = false; + + self.init( initialFunctions || [] ); + self.start(); + + return self; +} + +/** add all fns in initialFunctions (if any) to the queue */ +AjaxQueue.prototype.init = function init( initialFunctions ){ + var self = this; + initialFunctions.forEach( function( fn ){ + self.add( fn ); + }); +}; + +/** add a fn to the queue */ +AjaxQueue.prototype.add = function add( fn ){ + //console.debug( 'AjaxQueue.prototype.add:', fn ); + var self = this, + index = this.queue.length; + this.numToProcess += 1; + + this.queue.push( function(){ + var xhr = fn(); + // if successful, notify using the deferred to allow tracking progress + xhr.done( function( response ){ + self.deferred.notify({ curr: index, total: self.numToProcess, response: response }); + }); + // (regardless of previous error or success) if not last ajax call, shift and call the next + // if last fn, resolve deferred + xhr.always( function( response ){ + self.responses.push( response ); + if( self.queue.length ){ + self.queue.shift()(); + } else { + self.stop(); + } + }); + }); +}; + +/** start processing the queue */ +AjaxQueue.prototype.start = function start(){ + if( this.queue.length ){ + this.running = true; + this.queue.shift()(); + } +}; + +/** stop the queue + * @param {boolean} causeFail cause an error/fail on the main deferred + * @param {String} msg message to send when rejecting the main deferred + */ +AjaxQueue.prototype.stop = function stop( causeFail, msg ){ + //TODO: doesn't abort current call + this.running = false; + this.queue = []; + if( causeFail ){ + //TODO: spliced args instead + this.deferred.reject( msg ); + } else { + this.deferred.resolve( this.responses ); + } + return this; +}; + +// only a handful of the deferred interface for now - possible YAGNI +/** implement done from the jq deferred interface */ +AjaxQueue.prototype.done = function done( fn ){ + return this.deferred.done( fn ); +}; +/** implement fail from the jq deferred interface */ +AjaxQueue.prototype.fail = function fail( fn ){ + return this.deferred.fail( fn ); +}; +/** implement always from the jq deferred interface */ +AjaxQueue.prototype.always = function always( fn ){ + return this.deferred.always( fn ); +}; +/** implement progress from the jq deferred interface */ +AjaxQueue.prototype.progress = function progress( fn ){ + return this.deferred.progress( fn ); +}; + +/** shortcut constructor / fire and forget + * @returns {Deferred} the queue's main deferred + */ +AjaxQueue.create = function create( initialFunctions ){ + return new AjaxQeueue( initialFunctions ).deferred; +}; + + +//============================================================================= +/** @class NamedAjaxQueue + * @augments AjaxQueue + * Allows associating a name with a deferring fn and prevents adding deferring + * fns if the name has already been used. Useful to prevent build up of duplicate + * async calls. + * Both the array initialFunctions sent to constructor and any added later with + * add() should be objects (NOT functions) of the form: + * { name: some unique id, + * fn: the deferring fn or ajax call } + */ +function NamedAjaxQueue( initialFunctions ){ + var self = this; + self.names = {}; + AjaxQueue.call( this, initialFunctions ); + return self; +} +NamedAjaxQueue.prototype = new AjaxQueue(); +NamedAjaxQueue.prototype.constructor = NamedAjaxQueue; + +/** add the obj.fn to the queue if obj.name hasn't been used before */ +NamedAjaxQueue.prototype.add = function add( obj ){ + //console.debug( 'NamedAjaxQueue.prototype.add:', obj ); + if( !( obj.hasOwnProperty( 'name' ) && obj.hasOwnProperty( 'fn' ) ) ){ + throw new Error( 'NamedAjaxQueue.add requires an object with both "name" and "fn": ' + JSON.stringify( obj ) ); + } + if( this.names.hasOwnProperty( obj.name ) ){ + //console.warn( 'name has been used:', obj.name ); + return; + } + this.names[ obj.name ] = true; + AjaxQueue.prototype.add.call( this, obj.fn ); +}; + +/** shortcut constructor / fire and forget + * @returns {Deferred} the queue's main deferred + */ +NamedAjaxQueue.create = function create( initialFunctions ){ + return new NamedAjaxQueue( initialFunctions ).deferred; +}; + + +//============================================================================= + return { + AjaxQueue : AjaxQueue, + NamedAjaxQueue : NamedAjaxQueue + }; +}); Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.
participants (1)
-
commits-noreply@bitbucket.org