Ich möchte eine Seite basierend auf den Ergebnissen mehrerer Ajax / JSON-Anfragen aktualisieren. Mit jQuery kann ich die Rückrufe "verketten", wie in diesem sehr einfachen Beispiel:
$.getJSON("/values/1", function(data) {
// data = {value: 1}
var value_1 = data.value;
$.getJSON("/values/2", function(data) {
// data = {value: 42}
var value_2 = data.value;
var sum = value_1 + value_2;
$('#mynode').html(sum);
});
});
Dies führt jedoch dazu, dass die Anforderungen seriell gestellt werden. Ich möchte lieber die Anforderungen parallel stellen und die Seitenaktualisierung durchführen, nachdem alle abgeschlossen sind. Gibt es eine Möglichkeit, dies zu tun?
javascript
jquery
ajax
Paul
quelle
quelle
jQuery $ .when () und $ .done () sind genau das, was Sie brauchen:
$.when($.ajax("/page1.php"), $.ajax("/page2.php")) .then(myFunc, myFailure);
quelle
Hier ist mein Versuch, Ihre Frage direkt zu beantworten
Grundsätzlich bauen Sie einfach einen AJAX-Aufrufstapel auf, führen sie alle aus und eine bereitgestellte Funktion wird nach Abschluss aller Ereignisse aufgerufen. Das angegebene Argument ist ein Array der Ergebnisse aller bereitgestellten Ajax-Anforderungen.
Dies ist eindeutig ein früher Code - Sie könnten diesbezüglich in Bezug auf die Flexibilität ausführlicher vorgehen.
<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script> <script type="text/javascript"> var ParallelAjaxExecuter = function( onComplete ) { this.requests = []; this.results = []; this.onComplete = onComplete; } ParallelAjaxExecuter.prototype.addRequest = function( method, url, data, format ) { this.requests.push( { "method" : method , "url" : url , "data" : data , "format" : format , "completed" : false } ) } ParallelAjaxExecuter.prototype.dispatchAll = function() { var self = this; $.each( self.requests, function( i, request ) { request.method( request.url, request.data, function( r ) { return function( data ) { console.log r.completed = true; self.results.push( data ); self.checkAndComplete(); } }( request ) ) } ) } ParallelAjaxExecuter.prototype.allRequestsCompleted = function() { var i = 0; while ( request = this.requests[i++] ) { if ( request.completed === false ) { return false; } } return true; }, ParallelAjaxExecuter.prototype.checkAndComplete = function() { if ( this.allRequestsCompleted() ) { this.onComplete( this.results ); } } var pe = new ParallelAjaxExecuter( function( results ) { alert( eval( results.join( '+' ) ) ); } ); pe.addRequest( $.get, 'test.php', {n:1}, 'text' ); pe.addRequest( $.get, 'test.php', {n:2}, 'text' ); pe.addRequest( $.get, 'test.php', {n:3}, 'text' ); pe.addRequest( $.get, 'test.php', {n:4}, 'text' ); pe.dispatchAll(); </script>
hier ist test.php
<?php echo pow( $_GET['n'], 2 ); ?>
quelle
Update: Laut der Antwort von Yair Leviel ist diese Antwort veraltet. Verwenden Sie eine Versprechensbibliothek wie jQuery.when () oder Q.js.
Ich habe eine Allzwecklösung als jQuery-Erweiterung erstellt. Könnte eine Feinabstimmung gebrauchen, um es allgemeiner zu machen, aber es entsprach meinen Bedürfnissen. Der Vorteil dieser Technik gegenüber den anderen in diesem Beitrag zum Zeitpunkt dieses Schreibens bestand darin, dass jede Art von asynchroner Verarbeitung mit einem Rückruf verwendet werden kann.
Hinweis: Ich würde stattdessen Rx-Erweiterungen für JavaScript verwenden, wenn ich dachte, mein Client wäre damit einverstanden, eine Abhängigkeit von einer weiteren Bibliothek eines Drittanbieters zu übernehmen :)
// jQuery extension for running multiple async methods in parallel // and getting a callback with all results when all of them have completed. // // Each worker is a function that takes a callback as its only argument, and // fires up an async process that calls this callback with its result. // // Example: // $.parallel( // function (callback) { $.get("form.htm", {}, callback, "html"); }, // function (callback) { $.post("data.aspx", {}, callback, "json"); }, // function (formHtml, dataJson) { // // Handle success; each argument to this function is // // the result of correlating ajax call above. // } // ); (function ($) { $.parallel = function (anyNumberOfWorkers, allDoneCallback) { var workers = []; var workersCompleteCallback = null; // To support any number of workers, use "arguments" variable to // access function arguments rather than the names above. var lastArgIndex = arguments.length - 1; $.each(arguments, function (index) { if (index == lastArgIndex) { workersCompleteCallback = this; } else { workers.push({ fn: this, done: false, result: null }); } }); // Short circuit this edge case if (workers.length == 0) { workersCompleteCallback(); return; } // Fire off each worker process, asking it to report back to onWorkerDone. $.each(workers, function (workerIndex) { var worker = this; var callback = function () { onWorkerDone(worker, arguments); }; worker.fn(callback); }); // Store results and update status as each item completes. // The [0] on workerResultS below assumes the client only needs the first parameter // passed into the return callback. This simplifies the handling in allDoneCallback, // but may need to be removed if you need access to all parameters of the result. // For example, $.post calls back with success(data, textStatus, XMLHttpRequest). If // you need textStatus or XMLHttpRequest then pull off the [0] below. function onWorkerDone(worker, workerResult) { worker.done = true; worker.result = workerResult[0]; // this is the [0] ref'd above. var allResults = []; for (var i = 0; i < workers.length; i++) { if (!workers[i].done) return; else allResults.push(workers[i].result); } workersCompleteCallback.apply(this, allResults); } }; })(jQuery);
quelle
Führen Sie mehrere AJAX-Anforderungen gleichzeitig aus
Wenn Sie mit APIs arbeiten, müssen Sie manchmal mehrere AJAX-Anforderungen an verschiedene Endpunkte senden. Anstatt auf die Fertigstellung einer Anforderung zu warten, bevor die nächste ausgegeben wird, können Sie die Arbeit mit jQuery beschleunigen, indem Sie die Daten mithilfe der
$.when()
Funktion von jQuery parallel anfordern :JS
$.when($.get('1.json'), $.get('2.json')).then(function(r1, r2){ console.log(r1[0].message + " " + r2[0].message); });
Die Rückruffunktion wird ausgeführt, wenn beide GET-Anforderungen erfolgreich abgeschlossen wurden.
$.when()
Nimmt die von zwei$.get()
Aufrufen zurückgegebenen Versprechen und erstellt ein neues Versprechenobjekt. Die Argumenter1
undr2
des Rückrufs sind Arrays, deren erste Elemente die Serverantworten enthalten.quelle
UPDATE Und weitere zwei Jahre später sieht das verrückt aus, weil sich die akzeptierte Antwort in etwas viel Besseres geändert hat! (Obwohl immer noch nicht so gut wie Yair Leviels Antwort mit jQuery's
when
)18 Monate später habe ich gerade etwas Ähnliches getroffen. Ich habe eine Schaltfläche zum Aktualisieren und möchte, dass der alte Inhalt
fadeOut
und dann der neue Inhalt angezeigt werdenfadeIn
. Ich brauche aber auchget
den neuen Inhalt. DiefadeOut
und dieget
sind asynchron, aber es wäre Zeitverschwendung, sie seriell auszuführen.Was ich tue, ist wirklich dasselbe wie die akzeptierte Antwort, außer in Form einer wiederverwendbaren Funktion. Seine Haupttugend ist, dass es viel kürzer ist als die anderen Vorschläge hier.
var parallel = function(actions, finished) { finishedCount = 0; var results = []; $.each(actions, function(i, action) { action(function(result) { results[i] = result; finishedCount++; if (finishedCount == actions.length) { finished(results); } }); }); };
Sie übergeben ihm eine Reihe von Funktionen, die parallel ausgeführt werden sollen. Jede Funktion sollte eine andere Funktion akzeptieren, an die sie ihr Ergebnis weitergibt (falls vorhanden).
parallel
wird diese Funktion liefern.Sie übergeben ihm auch eine Funktion, die aufgerufen werden soll, wenn alle Vorgänge abgeschlossen sind. Dies erhält ein Array mit allen Ergebnissen in. Mein Beispiel war also:
refreshButton.click(function() { parallel([ function(f) { contentDiv.fadeOut(f); }, function(f) { portlet.content(f); }, ], function(results) { contentDiv.children().remove(); contentDiv.append(results[1]); contentDiv.fadeIn(); }); });
Wenn Sie also auf die Schaltfläche "Aktualisieren" klicken, starte ich den
fadeOut
Effekt von jQuery und meine eigeneportlet.content
Funktion (die eine Asynchronisierung ausführtget
, ein neues Stück Inhalt erstellt und weiterleitet). Wenn beide abgeschlossen sind, entferne ich den alten Inhalt und füge das Ergebnis hinzu der zweiten Funktion (die in istresults[1]
) undfadeIn
des neuen Inhalts.Da
fadeOut
nichts an seine Vervollständigungsfunktion übergeben wird,results[0]
vermutlich enthältundefined
, ignoriere ich es. Wenn Sie jedoch drei Operationen mit nützlichen Ergebnissen hätten, würden sie jeweils inresults
derselben Reihenfolge in das Array eingesteckt, in der Sie die Funktionen übergeben haben.quelle
Sie könnten so etwas tun
var allData = [] $.getJSON("/values/1", function(data) { allData.push(data); if(data.length == 2){ processData(allData) // where process data processes all the data } }); $.getJSON("/values/2", function(data) { allData.push(data); if(data.length == 2){ processData(allData) // where process data processes all the data } }); var processData = function(data){ var sum = data[0] + data[1] $('#mynode').html(sum); }
quelle
Hier ist eine Implementierung mit mbostock / queue :
queue() .defer(function(callback) { $.post('/echo/json/', {json: JSON.stringify({value: 1}), delay: 1}, function(data) { callback(null, data.value); }); }) .defer(function(callback) { $.post('/echo/json/', {json: JSON.stringify({value: 3}), delay: 2}, function(data) { callback(null, data.value); }); }) .awaitAll(function(err, results) { var result = results.reduce(function(acc, value) { return acc + value; }, 0); console.log(result); });
Die zugehörige Geige: http://jsfiddle.net/MdbW2/
quelle
Mit der folgenden Erweiterung von JQuery (kann als eigenständige Funktion geschrieben werden) können Sie dies tun:
$.whenAll({ val1: $.getJSON('/values/1'), val2: $.getJSON('/values/2') }) .done(function (results) { var sum = results.val1.value + results.val2.value; $('#mynode').html(sum); });
Die JQuery (1.x) -Erweiterung whenAll ():
$.whenAll = function (deferreds) { function isPromise(fn) { return fn && typeof fn.then === 'function' && String($.Deferred().then) === String(fn.then); } var d = $.Deferred(), keys = Object.keys(deferreds), args = keys.map(function (k) { return $.Deferred(function (d) { var fn = deferreds[k]; (isPromise(fn) ? fn : $.Deferred(fn)) .done(d.resolve) .fail(function (err) { d.reject(err, k); }) ; }); }); $.when.apply(this, args) .done(function () { var resObj = {}, resArgs = Array.prototype.slice.call(arguments); resArgs.forEach(function (v, i) { resObj[keys[i]] = v; }); d.resolve(resObj); }) .fail(d.reject); return d; };
Siehe jsbin-Beispiel: http://jsbin.com/nuxuciwabu/edit?js,console
quelle
Die professionellste Lösung für mich wäre die Verwendung von async.js und Array.reduce wie folgt:
async.map([1, 2, 3, 4, 5], function (number, callback) { $.getJSON("/values/" + number, function (data) { callback(null, data.value); }); }, function (err, results) { $("#mynode").html(results.reduce(function(previousValue, currentValue) { return previousValue + currentValue; })); });
quelle
Wenn das Ergebnis einer Anforderung von der anderen abhängt, können Sie sie nicht parallel schalten.
quelle
Aufbauend auf Yairs Antwort. Sie können die Ajax-Versprechen dynamisch definieren.
var start = 1; // starting value var len = 2; // no. of requests var promises = (new Array(len)).fill().map(function() { return $.ajax("/values/" + i++); }); $.when.apply($, promises) .then(myFunc, myFailure);
quelle
Angenommen, Sie haben ein Array mit Dateinamen.
var templateNameArray=["test.html","test2.html","test3.html"]; htmlTemplatesLoadStateMap={}; var deffereds=[]; for (var i = 0; i < templateNameArray.length; i++) { if (!htmlTemplatesLoadStateMap[templateNameArray[i]]) { deferreds.push($.get("./Content/templates/" +templateNameArray[i], function (response, status, xhr) { if (status == "error") { } else { $("body").append(response); } })); htmlTemplatesLoadStateMap[templateNameArray[i]] = true; } } $.when.all(deferreds).always(function(resultsArray) { yourfunctionTobeExecuted(yourPayload); });
quelle