├── 0.html ├── 1.php ├── 2.php ├── 3.php ├── README ├── index.html └── jquery.ajaxmanager.js /0.html: -------------------------------------------------------------------------------- 1 | 0 seconds -------------------------------------------------------------------------------- /1.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /2.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /3.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aFarkas/Ajaxmanager/7aba194323cbc4bf6c0b71fdfb5e28dd030c54e5/README -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jQuery: AJAX Queue/Cache/Abort/Block Manager 6 | 7 | 8 | 15 | 16 | 17 | 24 | 25 | 26 | 152 | 153 | 154 |
155 |

AJAX Queue/Cache/Abort/Block Manager v. 3.0

156 |

Helps you to manage AJAX requests and responses (i.e. abort requests, block requests, order requests). It is inspired by the AJAX Queue Plugin and the AjaxQueue document in the jQuery-Wiki.

157 |

$.manageAjax.create (uniqueName, options)

158 |

Creates a new ajaxmanager and returns it. Takes a list of options:

159 | 172 |

Your constructed ajaxmanager knows the following methods:

173 | 185 |

Note:

186 |

First you have to construct/configure a new Ajaxmanager

187 | //create an ajaxmanager named someAjaxProfileName 188 | var someManagedAjax = $.manageAjax.create('someAjaxProfileName', { 189 | queue: true, 190 | cacheResponse: true 191 | }); 192 |

193 | 194 |

You have two different ways to call your methods (don´t mix them).

195 | 196 |

Calling Ajaxmanager with uniqueName

197 | //and add an ajaxrequest 198 | $.manageAjax.add('someAjaxProfileName', { 199 | success: function(html) { 200 | $('ul').append('<li>'+html+'</li>'); 201 | }, 202 | url: 'test.html' 203 | });

204 | 205 |

Calling Ajaxmanager with the returned ajaxmanger-Object

206 | //and add an ajaxrequest with the returned object 207 | $.manageAjax.add({ 208 | success: function(html) { 209 | $('ul').append('<li>'+html+'</li>'); 210 | }, 211 | url: 'test.html' 212 | });

213 | 214 |

Example:

215 |

216 | //create an ajaxmanager named cacheQueue 217 | var ajaxManager = $.manageAjax.create('cacheQueue', { 218 | queue: true, 219 | cacheResponse: true 220 | }); 221 | //and add an ajaxrequest with the returned object 222 | ajaxManager.add({ 223 | success: function(html) { 224 | $('ul').append('<li>'+html+'</li>'); 225 | }, 226 | url: 'test.html' 227 | });

228 |

or only with the uniqueName parameter

229 |

230 | //generate an ajaxmanger named clearQueue 231 | $.manageAjax.create('clearQueue', {queue: 'clear', maxRequests: 2}); 232 | //and add an ajaxrequest with the name parameter 233 | $.manageAjax.add('clearQueue', { 234 | success: function(html) { 235 | $('ul').append('<li>'+html+'</li>'); 236 | }, 237 | url: 'test.html' 238 | });

239 |

$.manageAjax.destroy (uniqueName)

240 |

Destroys an existing Ajaxmanager. Any requests in progress are aborted and waiting requests are cleared.

241 |

Events/Callbacks:

242 |

The ajaxmanager adds some new events or enhances some existing callbacks.

243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 273 | 274 | 275 | 276 | 277 | 280 | 281 | 282 | 283 | 284 | 287 | 288 | 289 | 290 | 291 | 294 | 295 | 296 | 297 | 298 | 301 | 302 | 303 | 304 | 305 | 308 | 309 | 310 | 311 | 312 | 315 | 316 | 317 | 318 | 319 | 322 | 323 | 324 | 325 | 326 | 329 | 330 | 331 | 332 |
nameargumentsnew/enhanced
beforeCreate (local)XHR-ID, optionsnew
beforeSend (local)XMLHttpRequest, optionsenhanced: options arguments is passed
managerName + 'AjaxStart' (global)eventnew
complete (local) 271 | xhr*, status, options 272 | enhanced: the options arguments is additionally passed.
managerName + 'AjaxComplete' (global) 278 | event, xhr*, status, options 279 | new
managerName + 'DOMComplete' (DOM-Event**) 285 | event, xhr*, status, options 286 | new
'DOMComplete' (DOM-Event**) 292 | event, xhr*, status, options 293 | new
success (local) 299 | data, textStatus, xhr*, options 300 | enhanced: the options arguments is additionally passed.
managerName + 'AjaxSuccess' (global) 306 | event, xhr, options, data 307 | new
managerName + 'DOMSuccess' (DOM-Event**) 313 | event, data, options 314 | new
'DOMSuccess' (DOM-Event**) 320 | event, data, options 321 | new
managerName + 'AjaxStop' (global) 327 | event 328 | new
333 |

*Note: If the cacheResponse - option is true, the xhr-argument can be an empty object.

334 |

**Note: You need to configure 'domCompleteTrigger' / 'domSuccessTrigger' to trigger these events.

335 |

Demo:

336 |

Tip: Open your Firebug-Console, log the XHR´s and click around.

337 |
338 |

{queue: true}

339 | 340 | 0 secound delay | 1 secound delay | 2 secounds delay | 3 secounds delay | 341 | 342 |
343 |
344 |

{queue: 'clear', maxRequests: 2, abortOld: true}

345 | 346 | 0 second delay | 1 second delay | 2 seconds delay | 3 secounds delay | 347 | 348 |
349 |
350 |

{queue: 'clear', cacheResponse: true}

351 | 352 | 0 second delay | 1 second delay | 2 seconds delay | 3 secounds delay | 353 | 354 |
355 |
356 |

{queue: false, cacheResponse: true, preventDoubleRequests: false}

357 | 358 | 0 second delay | 1 second delay | 2 seconds delay | 3 secounds delay | 359 | 360 |
361 |

If you find bugs please report them!!!

362 |

Project Site & Bugtracker

363 | 367 |

Download

368 | 371 |

Licenses

372 | 376 |

Back to protofunc

377 |
378 | 379 | 380 | -------------------------------------------------------------------------------- /jquery.ajaxmanager.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * project-site: http://plugins.jquery.com/project/AjaxManager 3 | * repository: http://github.com/aFarkas/Ajaxmanager 4 | * @author Alexander Farkas 5 | * @version 3.12 6 | * Copyright 2010, Alexander Farkas 7 | * Dual licensed under the MIT or GPL Version 2 licenses. 8 | */ 9 | 10 | (function($){ 11 | "use strict"; 12 | var managed = {}, 13 | cache = {} 14 | ; 15 | $.manageAjax = (function(){ 16 | function create(name, opts){ 17 | managed[name] = new $.manageAjax._manager(name, opts); 18 | return managed[name]; 19 | } 20 | 21 | function destroy(name){ 22 | if(managed[name]){ 23 | managed[name].clear(true); 24 | delete managed[name]; 25 | } 26 | } 27 | 28 | 29 | var publicFns = { 30 | create: create, 31 | destroy: destroy 32 | }; 33 | 34 | return publicFns; 35 | })(); 36 | 37 | $.manageAjax._manager = function(name, opts){ 38 | this.requests = {}; 39 | this.inProgress = 0; 40 | this.name = name; 41 | this.qName = name; 42 | 43 | this.opts = $.extend({}, $.manageAjax.defaults, opts); 44 | if(opts && opts.queue && opts.queue !== true && typeof opts.queue === 'string' && opts.queue !== 'clear'){ 45 | this.qName = opts.queue; 46 | } 47 | }; 48 | 49 | $.manageAjax._manager.prototype = { 50 | add: function(url, o){ 51 | if(typeof url == 'object'){ 52 | o = url; 53 | } else if(typeof url == 'string'){ 54 | o = $.extend(o || {}, {url: url}); 55 | } 56 | o = $.extend({}, this.opts, o); 57 | 58 | var origCom = o.complete || $.noop, 59 | origSuc = o.success || $.noop, 60 | beforeSend = o.beforeSend || $.noop, 61 | origError = o.error || $.noop, 62 | strData = (typeof o.data == 'string') ? o.data : $.param(o.data || {}), 63 | xhrID = o.type + o.url + strData, 64 | that = this, 65 | ajaxFn = this._createAjax(xhrID, o, origSuc, origCom) 66 | ; 67 | if(o.preventDoubleRequests && o.queueDuplicateRequests){ 68 | if(o.preventDoubleRequests){ 69 | o.queueDuplicateRequests = false; 70 | } 71 | setTimeout(function(){ 72 | throw("preventDoubleRequests and queueDuplicateRequests can't be both true"); 73 | }, 0); 74 | } 75 | if(this.requests[xhrID] && o.preventDoubleRequests){ 76 | return; 77 | } 78 | ajaxFn.xhrID = xhrID; 79 | o.xhrID = xhrID; 80 | 81 | o.beforeSend = function(xhr, opts){ 82 | var ret = beforeSend.call(this, xhr, opts); 83 | if(ret === false){ 84 | that._removeXHR(xhrID); 85 | } 86 | xhr = null; 87 | return ret; 88 | }; 89 | o.complete = function(xhr, status){ 90 | that._complete.call(that, this, origCom, xhr, status, xhrID, o); 91 | xhr = null; 92 | }; 93 | 94 | o.success = function(data, status, xhr){ 95 | that._success.call(that, this, origSuc, data, status, xhr, o); 96 | xhr = null; 97 | }; 98 | 99 | //always add some error callback 100 | o.error = function(ahr, status, errorStr){ 101 | var httpStatus = '', 102 | content = '' 103 | ; 104 | if(status !== 'timeout' && ahr){ 105 | httpStatus = ahr.status; 106 | content = ahr.responseXML || ahr.responseText; 107 | } 108 | if(origError) { 109 | origError.call(this, ahr, status, errorStr, o); 110 | } else { 111 | setTimeout(function(){ 112 | throw status + '| status: ' + httpStatus + ' | URL: ' + o.url + ' | data: '+ strData + ' | thrown: '+ errorStr + ' | response: '+ content; 113 | }, 0); 114 | } 115 | ahr = null; 116 | }; 117 | 118 | if(o.queue === 'clear'){ 119 | $(document).clearQueue(this.qName); 120 | } 121 | 122 | if(o.queue || (o.queueDuplicateRequests && this.requests[xhrID])){ 123 | $.queue(document, this.qName, ajaxFn); 124 | if(this.inProgress < o.maxRequests && (!this.requests[xhrID] || !o.queueDuplicateRequests)){ 125 | $.dequeue(document, this.qName); 126 | } 127 | return xhrID; 128 | } 129 | return ajaxFn(); 130 | }, 131 | _createAjax: function(id, o, origSuc, origCom){ 132 | var that = this; 133 | return function(){ 134 | if(o.beforeCreate.call(o.context || that, id, o) === false){return;} 135 | that.inProgress++; 136 | if(that.inProgress === 1){ 137 | $.event.trigger(that.name +'AjaxStart'); 138 | } 139 | if(o.cacheResponse && cache[id]){ 140 | if(!cache[id].cacheTTL || cache[id].cacheTTL < 0 || ((new Date().getTime() - cache[id].timestamp) < cache[id].cacheTTL)){ 141 | that.requests[id] = {}; 142 | setTimeout(function(){ 143 | that._success.call(that, o.context || o, origSuc, cache[id]._successData, 'success', cache[id], o); 144 | that._complete.call(that, o.context || o, origCom, cache[id], 'success', id, o); 145 | }, 0); 146 | } else { 147 | delete cache[id]; 148 | } 149 | } 150 | if(!o.cacheResponse || !cache[id]) { 151 | if (o.async) { 152 | that.requests[id] = $.ajax(o); 153 | } else { 154 | $.ajax(o); 155 | } 156 | } 157 | return id; 158 | }; 159 | }, 160 | _removeXHR: function(xhrID){ 161 | if(this.opts.queue || this.opts.queueDuplicateRequests){ 162 | $.dequeue(document, this.qName); 163 | } 164 | this.inProgress--; 165 | this.requests[xhrID] = null; 166 | delete this.requests[xhrID]; 167 | }, 168 | clearCache: function () { 169 | cache = {}; 170 | }, 171 | _isAbort: function(xhr, status, o){ 172 | if(!o.abortIsNoSuccess || (!xhr && !status)){ 173 | return false; 174 | } 175 | var ret = !!( ( !xhr || xhr.readyState === 0 || this.lastAbort === o.xhrID ) ); 176 | xhr = null; 177 | return ret; 178 | }, 179 | _complete: function(context, origFn, xhr, status, xhrID, o){ 180 | if(this._isAbort(xhr, status, o)){ 181 | status = 'abort'; 182 | o.abort.call(context, xhr, status, o); 183 | } 184 | origFn.call(context, xhr, status, o); 185 | 186 | $.event.trigger(this.name +'AjaxComplete', [xhr, status, o]); 187 | 188 | if(o.domCompleteTrigger){ 189 | $(o.domCompleteTrigger) 190 | .trigger(this.name +'DOMComplete', [xhr, status, o]) 191 | .trigger('DOMComplete', [xhr, status, o]) 192 | ; 193 | } 194 | 195 | this._removeXHR(xhrID); 196 | if(!this.inProgress){ 197 | $.event.trigger(this.name +'AjaxStop'); 198 | } 199 | xhr = null; 200 | }, 201 | _success: function(context, origFn, data, status, xhr, o){ 202 | var that = this; 203 | if(this._isAbort(xhr, status, o)){ 204 | xhr = null; 205 | return; 206 | } 207 | if(o.abortOld){ 208 | $.each(this.requests, function(name){ 209 | if(name === o.xhrID){ 210 | return false; 211 | } 212 | that.abort(name); 213 | }); 214 | } 215 | if(o.cacheResponse && !cache[o.xhrID]){ 216 | if(!xhr){ 217 | xhr = {}; 218 | } 219 | cache[o.xhrID] = { 220 | status: xhr.status, 221 | statusText: xhr.statusText, 222 | responseText: xhr.responseText, 223 | responseXML: xhr.responseXML, 224 | _successData: data, 225 | cacheTTL: o.cacheTTL, 226 | timestamp: new Date().getTime() 227 | }; 228 | if('getAllResponseHeaders' in xhr){ 229 | var responseHeaders = xhr.getAllResponseHeaders(); 230 | var parsedHeaders; 231 | var parseHeaders = function(){ 232 | if(parsedHeaders){return;} 233 | parsedHeaders = {}; 234 | $.each(responseHeaders.split("\n"), function(i, headerLine){ 235 | var delimiter = headerLine.indexOf(":"); 236 | parsedHeaders[headerLine.substr(0, delimiter)] = headerLine.substr(delimiter + 2); 237 | }); 238 | }; 239 | $.extend(cache[o.xhrID], { 240 | getAllResponseHeaders: function() {return responseHeaders;}, 241 | getResponseHeader: function(name) { 242 | parseHeaders(); 243 | return (name in parsedHeaders) ? parsedHeaders[name] : null; 244 | } 245 | }); 246 | } 247 | } 248 | origFn.call(context, data, status, xhr, o); 249 | $.event.trigger(this.name +'AjaxSuccess', [xhr, o, data]); 250 | if(o.domSuccessTrigger){ 251 | $(o.domSuccessTrigger) 252 | .trigger(this.name +'DOMSuccess', [data, o]) 253 | .trigger('DOMSuccess', [data, o]) 254 | ; 255 | } 256 | xhr = null; 257 | }, 258 | getData: function(id){ 259 | if( id ){ 260 | var ret = this.requests[id]; 261 | if(!ret && this.opts.queue) { 262 | ret = $.grep($(document).queue(this.qName), function(fn, i){ 263 | return (fn.xhrID === id); 264 | })[0]; 265 | } 266 | return ret; 267 | } 268 | return { 269 | requests: this.requests, 270 | queue: (this.opts.queue) ? $(document).queue(this.qName) : [], 271 | inProgress: this.inProgress 272 | }; 273 | }, 274 | abort: function(id){ 275 | var xhr; 276 | if(id){ 277 | xhr = this.getData(id); 278 | 279 | if(xhr && xhr.abort){ 280 | this.lastAbort = id; 281 | xhr.abort(); 282 | this.lastAbort = false; 283 | } else { 284 | $(document).queue( 285 | this.qName, $.grep($(document).queue(this.qName), function(fn, i){ 286 | return (fn !== xhr); 287 | }) 288 | ); 289 | } 290 | xhr = null; 291 | return; 292 | } 293 | 294 | var that = this, 295 | ids = [] 296 | ; 297 | $.each(this.requests, function(id){ 298 | ids.push(id); 299 | }); 300 | $.each(ids, function(i, id){ 301 | that.abort(id); 302 | }); 303 | }, 304 | clear: function(shouldAbort){ 305 | $(document).clearQueue(this.qName); 306 | if(shouldAbort){ 307 | this.abort(); 308 | } 309 | } 310 | }; 311 | $.manageAjax._manager.prototype.getXHR = $.manageAjax._manager.prototype.getData; 312 | $.manageAjax.defaults = { 313 | beforeCreate: $.noop, 314 | abort: $.noop, 315 | abortIsNoSuccess: true, 316 | maxRequests: 1, 317 | cacheResponse: false, 318 | async: true, 319 | domCompleteTrigger: false, 320 | domSuccessTrigger: false, 321 | preventDoubleRequests: true, 322 | queueDuplicateRequests: false, 323 | cacheTTL: -1, 324 | queue: false // true, false, clear 325 | }; 326 | 327 | $.each($.manageAjax._manager.prototype, function(n, fn){ 328 | if(n.indexOf('_') === 0 || !$.isFunction(fn)){return;} 329 | $.manageAjax[n] = function(name, o){ 330 | if(!managed[name]){ 331 | if(n === 'add'){ 332 | $.manageAjax.create(name, o); 333 | } else { 334 | return; 335 | } 336 | } 337 | var args = Array.prototype.slice.call(arguments, 1); 338 | managed[name][n].apply(managed[name], args); 339 | }; 340 | }); 341 | 342 | })(jQuery); --------------------------------------------------------------------------------