Queue Ajax Anfragen mit jQuery.queue ()

Ich benutze jQuery.queue () zum ersten Mal und habe es nicht ganz verstanden. Könnte jemand bitte darauf hinweisen, was ich falsch mache?

Wenn ich im Firebug sehe, sehe ich immer noch, dass meine POST-Anfragen zur gleichen Zeit ausgetriggers werden – also frage ich mich, ob ich an der falschen Stelle () ausqueue ().

Auch – wie bekomme ich die Warteschlangenlänge?

Der Grund, warum ich diese Anfragen in die Warteschlange stellen muss, besteht darin, dass sie auf einen Klick ausgetriggers wird. Und es ist für den Benutzer möglich, mehrere Tasten in schneller Folge anzuklicken.

Versucht, die Grundstruktur meines Codes zu entfernen:

$("a.button").click(function(){ $(this).doAjax(params); }); // method doAjax:function(params){ $(document).queue("myQueueName", function(){ $.ajax({ type: 'POST', url: 'whatever.html', params: params, success: function(data){ doStuff; $(document).dequeue("myQueueName"); } }); }); } 

Ihr Problem hier ist, dass .ajax() eine asynchrone laufende Ajax Anfrage austriggers. Das bedeutet, dass .ajax() sofort zurückgibt, nicht blockierend. Also die Warteschlange die functionen aber sie werden fast zur gleichen Zeit wie Sie beschrieben feuern.

Ich denke nicht, dass die .queue() ein guter Ort ist, um Ajax-Anfragen zu haben, es ist eher für die Verwendung von fx methods gedacht. Sie brauchen einen einfachen Manager.

 var ajaxManager = (function() { var requests = []; return { addReq: function(opt) { requests.push(opt); }, removeReq: function(opt) { if( $.inArray(opt, requests) > -1 ) requests.splice($.inArray(opt, requests), 1); }, run: function() { var self = this, oriSuc; if( requests.length ) { oriSuc = requests[0].complete; requests[0].complete = function() { if( typeof(oriSuc) === 'function' ) oriSuc(); requests.shift(); self.run.apply(self, []); }; $.ajax(requests[0]); } else { self.tid = setTimeout(function() { self.run.apply(self, []); }, 1000); } }, stop: function() { requests = []; clearTimeout(this.tid); } }; }()); 

Das ist weit davon entfernt, perfekt zu sein, ich möchte nur den Weg demonstrieren. Das obige Beispiel könnte in ähnlicher Weise verwendet werden

 $(function() { ajaxManager.run(); $("a.button").click(function(){ ajaxManager.addReq({ type: 'POST', url: 'whatever.html', data: params, success: function(data){ // do stuff } }); }); }); 

Ich musste etwas Ähnliches machen und dachte, ich würde hier meine Lösung posten.

Grundsätzlich habe ich eine Seite, die Projekte in Regalen auflistet, die alle unterscheidbare Kriterien haben. Ich wollte die Regale eins nach dem anderen laden, anstatt alles zusammenzustellen, um dem Benutzer schneller Inhalte zu liefern, die er sich ansehen kann, während der Rest geladen wird.

Grundsätzlich habe ich die ID jedes Shelfs in einem JS-Array gespeichert, das ich benutze, wenn ich sie von PHP aus anrufe.

Ich habe dann eine rekursive function erstellt, die den ersten Index bei jedem Aufruf aus dem Array herausholt und das Shelf für die Pop-ID anfordert. Sobald ich die Antwort von $.get() oder $.post() was auch immer ich bevorzuge, dann rufe ich die rekursive function aus dem Callback heraus.

Hier ist eine Ausarbeitung im Code:

 // array of shelf IDs var shelves = new Array(1,2,3,4); // the recursive function function getShelfRecursive() { // terminate if array exhausted if (shelves.length === 0) return; // pop top value var id = shelves[0]; shelves.shift(); // ajax request $.get('/get/shelf/' + id, function(){ // call completed - so start next request getShelfRecursive(); }); } // fires off the first call getShelfRecursive(); 

Ich musste dies für eine unbekannte Anzahl von Ajax-Anrufen tun. Die Antwort war, jeden in ein Array zu schieben und dann zu verwenden:

 $.when.apply($, arrayOfDeferreds).done(function () { alert("All done"); }); 

Ich fand die obigen Lösungen irgendwie kompliziert, und ich musste die Anfrage kurz vor dem Senden ändern (um ein neues Daten-Token zu aktualisieren).

Also lege ich das hier zusammen. Quelle: https://gist.github.com/2470554

 /* Allows for ajax requests to be run synchronously in a queue Usage:: var queue = new $.AjaxQueue(); queue.add({ url: 'url', complete: function() { console.log('ajax completed'); }, _run: function(req) { //special pre-processor to alter the request just before it is finally executed in the queue req.url = 'changed_url' } }); */ $.AjaxQueue = function() { this.reqs = []; this.requesting = false; }; $.AjaxQueue.prototype = { add: function(req) { this.reqs.push(req); this.next(); }, next: function() { if (this.reqs.length == 0) return; if (this.requesting == true) return; var req = this.reqs.splice(0, 1)[0]; var complete = req.complete; var self = this; if (req._run) req._run(req); req.complete = function() { if (complete) complete.apply(this, arguments); self.requesting = false; self.next(); } this.requesting = true; $.ajax(req); } }; 

Ich benutze diesen sehr einfachen Code, um zu verhindern, dass sich Ajax-Anrufe gegenseitig “überholen”.

 var dopostqueue = $({}); function doPost(string, callback) { dopostqueue.queue(function() { $.ajax( { type: 'POST', url: 'thephpfile.php', datatype: 'json', data: string, success:function(result) { dopostqueue.dequeue(); callback(JSON.parse(result)); } }) }); } 

Wenn Sie nicht möchten, dass die Warteschlange sich selbst behandelt, können Sie einfach die dequeue aus der function entfernen und sie von einer anderen function aufrufen. Um die Warteschlangenlänge zu erhalten, wäre es für dieses Beispiel:

 dopostqueue.queue().length 

Sie könnten jQuery erweitern:

 (function($) { // Empty object, we are going to use this as our Queue var ajaxQueue = $({}); $.ajaxQueue = function(ajaxOpts) { // hold the original complete function var oldComplete = ajaxOpts.complete; // queue our ajax request ajaxQueue.queue(function(next) { // create a complete callback to fire the next event in the queue ajaxOpts.complete = function() { // fire the original complete if it was there if (oldComplete) oldComplete.apply(this, arguments); next(); // run the next query in the queue }; // run the query $.ajax(ajaxOpts); }); }; })(jQuery); 

dann benutze es wie:

 $.ajaxQueue({ url: 'doThisFirst.php', async: true, success: function (data) { //success handler }, error: function (jqXHR,textStatus,errorThrown) { //error Handler } }); $.ajaxQueue({ url: 'doThisSecond.php', async: true, success: function (data) { //success handler }, error: function (jqXHR,textStatus,errorThrown) { //error Handler } }); 

Natürlich können Sie auch andere $ .ajax Optionen wie type, data, contentType, DataType verwenden, da wir $ .ajax erweitern

Eine andere Version von jAndy’s Antwort, ohne Timer.

 var ajaxManager = { requests: [], addReq: function(opt) { this.requests.push(opt); if (this.requests.length == 1) { this.run(); } }, removeReq: function(opt) { if($.inArray(opt, requests) > -1) this.requests.splice($.inArray(opt, requests), 1); }, run: function() { // original complete callback oricomplete = this.requests[0].complete; // override complete callback var ajxmgr = this; ajxmgr.requests[0].complete = function() { if (typeof oricomplete === 'function') oricomplete(); ajxmgr.requests.shift(); if (ajxmgr.requests.length > 0) { ajxmgr.run(); } }; $.ajax(this.requests[0]); }, stop: function() { this.requests = []; }, } 

Benutzen:

 $(function() { $("a.button").click(function(){ ajaxManager.addReq({ type: 'POST', url: 'whatever.html', data: params, success: function(data){ // do stuff } }); }); }); 

Die Website learn.jquery.com hat auch ein gutes Beispiel :

 // jQuery on an empty object, we are going to use this as our queue var ajaxQueue = $({}); $.ajaxQueue = function(ajaxOpts) { // Hold the original complete function var oldComplete = ajaxOpts.complete; // Queue our ajax request ajaxQueue.queue(function(next) { // Create a complete callback to invoke the next event in the queue ajaxOpts.complete = function() { // Invoke the original complete if it was there if (oldComplete) { oldComplete.apply(this, arguments); } // Run the next query in the queue next(); }; // Run the query $.ajax(ajaxOpts); }); }; // Get each item we want to copy $("#items li").each(function(idx) { // Queue up an ajax request $.ajaxQueue({ url: "/ajax_html_echo/", data: { html: "[" + idx + "] " + $(this).html() }, type: "POST", success: function(data) { // Write to #output $("#output").append($("
  • ", { html: data })); } }); });
  • Ich musste dies auch innerhalb einer Lösung tun, die ich hatte und ich fand, dass ich es so machen konnte:

     //A variable for making sure to wait for multiple clicks before emptying. var waitingTimeout; $("a.button").click(function(){ $(this).doAjax(params); clearTimeout(waitingTimeout); waitingTimeout = setTimeout(function(){noMoreClicks();},1000); }); // method doAjax:function(params){ $(document).queue("myQueueName", function(next){ $.ajax({ type: 'POST', url: 'whatever.html', data: params, contentType: "application/json; charset=utf-8", dataType: "json", success: function(data){ doStuff; next(); }, failure: function(data){ next(); }, error: function(data){ next(); } }); }); } function noMoreClicks(){ $(document).dequeue("myQueueName"); } 

    Mit dem next() Callback, der in der Warteschlangenfunktion übergeben wird, können Sie die nächste Operation aus der Warteschlange nehmen. Indem Sie also den nächsten in die Handler für den Ajax setzen, bewirken Sie, dass der Ajax asynchron zum Browser und dem Render- oder Paint-Thread des Browsers aufruft, sie aber synchron oder seriell zueinander macht.

    Hier ist ein sehr einfaches Beispiel. In der Beispielgeige. Klicken Sie einmal auf die Schaltfläche und warten Sie eine Sekunde. Sie werden sehen, dass die Zeitüberschreitung ausgetriggers wird und die einzelne Operation ausgeführt wird. Klicken Sie anschließend so schnell wie möglich auf die Schaltfläche (oder schneller als eine Sekunde) und Sie werden feststellen, dass bei jedem Klicken auf die Schaltfläche die Vorgänge in die Warteschlange eingereiht werden und erst nach einer Sekunde auf die Seite und dann auf eine weitere eingeblendet werden das andere.

    Das Schöne daran ist, dass, wenn die Warteschlange bereits leer ist, alle Operationen, die Sie während des Leerens hinzugefügt haben, am Ende platziert und dann gerade verarbeitet werden, wenn die Zeit gekommen ist.

    Hier ist meine Lösung, mit der ich Anfragen für ein Browsergame erstellen kann. Wenn irgendetwas passiert, höre ich diese Warteschlange auf und beende die Arbeit mit einer speziellen letzten Anfrage oder Säuberung.

     var get_array = ["first", "second", "third"]; var worker = $("
    "); // to line up requests in queue $.queuedAjax = function(args){ // add up requests for me worker.queue( function(next){ $.ajax(args).always(next); } ); }; $.queuedSomething = function(){ // add up something special for me worker.queue( function(next){ //worker.clearQueue(); //worker = $("
    "); //cleanup for next .each //maybe another .each } ); }; $.each( get_array , function( key , value ) { $.queuedAjax({ type: 'GET', url: '/some.php?get='+value, dataType: 'text', success: function(sourcecode){ if (sourcecode.match(/stop your requests, idiot!/)) { worker.clearQueue().queue($.queuedSomething); alert(' the server told me to stop. i stopped all but not the last ´$.queuedSomething()´ '); } } }); }); $.queuedSomething();

    nur ein weiteres Beispiel für einen Multi-Thread-Warteschlangen-Runner, den ich für Nodejs geschrieben habe. Sie könnten es an jQuery oder eckig anpassen. Versprechen sind in jeder API leicht unterschiedlich. Ich habe dieses Muster für Dinge wie das Extrahieren aller Elemente aus großen Listen in SharePoint verwendet, indem mehrere Abfragen erstellt wurden, um alle Daten abzurufen und gleichzeitig 6 zuzulassen, um Beschränkungen durch Serverbeschränkungen zu vermeiden.

     /* Job Queue Runner (works with nodejs promises): Add functions that return a promise, set the number of allowed simultaneous threads, and then run (*) May need adaptation if used with jquery or angular promises Usage: var sourcesQueue = new QueueRunner('SourcesQueue'); sourcesQueue.maxThreads = 1; childSources.forEach(function(source) { sourcesQueue.addJob(function() { // Job function - perform work on source }); } sourcesQueue.run().then(function(){ // Queue complete... }); */ var QueueRunner = (function () { function QueueRunner(id) { this.maxThreads = 1; // Number of allowed simultaneous threads this.jobQueue = []; this.threadCount = 0; this.jobQueueConsumer = null; this.jobsStarted = 0; if(typeof(id) !== 'undefined') { this.id = id; } else { this.id = 'QueueRunner'; } } QueueRunner.prototype.run = function () { var instance = this; return new Promise(function(resolve, reject) { instance.jobQueueConsumer = setInterval(function() { if(instance.threadCount < instance.maxThreads && instance.jobQueue.length > 0) { instance.threadCount++; instance.jobsStarted++; // Remove the next job from the queue (index zero) and run it var job = instance.jobQueue.splice(0, 1)[0]; logger.info(instance.id + ': Start job ' + instance.jobsStarted + ' of ' + (instance.jobQueue.length + instance.jobsStarted)); job().then(function(){ instance.threadCount--; }, function(){ instance.threadCount--; }); } if(instance.threadCount < 1 && instance.jobQueue.length < 1) { clearInterval(instance.jobQueueConsumer); logger.info(instance.id + ': All jobs done.'); resolve(); } }, 20); }); }; QueueRunner.prototype.addJob = function (func) { this.jobQueue.push(func); }; return QueueRunner; }());