Chcę wykonać trzy wywołania Ajax w przypadku kliknięcia. Każde wywołanie Ajax wykonuje odrębną operację i zwraca dane potrzebne do końcowego wywołania zwrotnego. Same połączenia nie są od siebie zależne, wszystkie mogą być odbierane w tym samym czasie, jednak chciałbym mieć ostatnie oddzwonienie, gdy wszystkie trzy zostaną zakończone.
$('#button').click(function() {
fun1();
fun2();
fun3();
//now do something else when the requests have done their 'success' callbacks.
});
var fun1= (function() {
$.ajax({/*code*/});
});
var fun2 = (function() {
$.ajax({/*code*/});
});
var fun3 = (function() {
$.ajax({/*code*/});
});
Odpowiedzi:
Oto obiekt wywołania zwrotnego, który napisałem, w którym możesz ustawić pojedyncze wywołanie zwrotne tak, aby uruchamiało się po zakończeniu wszystkich lub pozwolić każdemu z nich mieć własne wywołanie zwrotne i uruchomić je wszystkie po zakończeniu:
OGŁOSZENIE
Od jQuery 1.5+ możesz używać metody odroczonej, jak opisano w innej odpowiedzi:
$.when($.ajax(), [...]).then(function(results){},[...]);
Przykład odroczonego tutaj
dla jQuery <1.5 zadziała poniższe działanie lub jeśli chcesz, aby wywołania ajax były uruchamiane w nieznanych momentach, jak pokazano tutaj z dwoma przyciskami: uruchamiane po kliknięciu obu przycisków
[stosowanie]
dla pojedynczego wywołania zwrotnego po zakończeniu: Przykład roboczy
// initialize here var requestCallback = new MyRequestsCompleted({ numRequest: 3, singleCallback: function(){ alert( "I'm the callback"); } }); //usage in request $.ajax({ url: '/echo/html/', success: function(data) { requestCallback.requestComplete(true); } }); $.ajax({ url: '/echo/html/', success: function(data) { requestCallback.requestComplete(true); } }); $.ajax({ url: '/echo/html/', success: function(data) { requestCallback.requestComplete(true); } });
każdy ma swoje własne wywołanie zwrotne po ukończeniu: Przykład roboczy
//initialize var requestCallback = new MyRequestsCompleted({ numRequest: 3 }); //usage in request $.ajax({ url: '/echo/html/', success: function(data) { requestCallback.addCallbackToQueue(true, function() { alert('Im the first callback'); }); } }); $.ajax({ url: '/echo/html/', success: function(data) { requestCallback.addCallbackToQueue(true, function() { alert('Im the second callback'); }); } }); $.ajax({ url: '/echo/html/', success: function(data) { requestCallback.addCallbackToQueue(true, function() { alert('Im the third callback'); }); } });
[Kod]
var MyRequestsCompleted = (function() { var numRequestToComplete, requestsCompleted, callBacks, singleCallBack; return function(options) { if (!options) options = {}; numRequestToComplete = options.numRequest || 0; requestsCompleted = options.requestsCompleted || 0; callBacks = []; var fireCallbacks = function() { alert("we're all complete"); for (var i = 0; i < callBacks.length; i++) callBacks[i](); }; if (options.singleCallback) callBacks.push(options.singleCallback); this.addCallbackToQueue = function(isComplete, callback) { if (isComplete) requestsCompleted++; if (callback) callBacks.push(callback); if (requestsCompleted == numRequestToComplete) fireCallbacks(); }; this.requestComplete = function(isComplete) { if (isComplete) requestsCompleted++; if (requestsCompleted == numRequestToComplete) fireCallbacks(); }; this.setCallback = function(callback) { callBacks.push(callBack); }; }; })();
źródło
setCallback
aby dodać więcej do kolejki. Chociaż teraz, kiedy o tym myślę ... Powinienem to nazwaćaddCallback
lub coś w tym rodzaju ... a nie tylko ustawić, ponieważ dodaje do kolejkisingleCallback
zmienna w drugim wierszu jest niepotrzebna? A może coś mi brakuje?Wygląda na to, że masz na to kilka odpowiedzi, jednak myślę, że jest tu coś, o czym warto wspomnieć, co znacznie uprości twój kod. jQuery wprowadził
$.when
w wersji 1.5. To wygląda jak:$.when($.ajax(...), $.ajax(...)).then(function (resp1, resp2) { //this callback will be fired once all ajax calls have finished. });
Nie widziałem tego tutaj, mam nadzieję, że to pomoże.
źródło
Sam nie widząc potrzeby jakiegokolwiek obiektu malarky. Simple ma zmienną, która jest liczbą całkowitą. Gdy zaczynasz żądanie, zwiększ liczbę. Kiedy skończysz, zmniejsz go. Kiedy jest zero, nie ma żadnych żądań w toku, więc gotowe.
$('#button').click(function() { var inProgress = 0; function handleBefore() { inProgress++; }; function handleComplete() { if (!--inProgress) { // do what's in here when all requests have completed. } }; $.ajax({ beforeSend: handleBefore, complete: function () { // whatever handleComplete(); // whatever } }); $.ajax({ beforeSend: handleBefore, complete: function () { // whatever handleComplete(); // whatever } }); $.ajax({ beforeSend: handleBefore, complete: function () { // whatever handleComplete(); // whatever } }); });
źródło
if (!--inProgress)
. Prawidłowa wersja jest analogiczna doinProgress = inProgress - 1; if (inProgress == 0) { /* do stuff */ }
. Forma zwarta łączy operator dekrementacji przedrostka (--
) i operator negacji (!
), aby obliczyć wartość „prawda” (i tym samym wykonaćif
blok), jeśliinProgress
wynikiem dekrementacji jestinProgress == 0
wartość „fałsz” (i dlatego nic nie robi).Warto zauważyć, że ponieważ
$.when
oczekuje, że wszystkie żądania AJAX są sekwencyjnymi argumentami (a nie tablicą), które są często$.when
używane z.apply()
takimi:// Save all requests in an array of jqXHR objects var requests = arrayOfThings.map(function(thing) { return $.ajax({ method: 'GET', url: 'thing/' + thing.id }); }); $.when.apply(this, requests).then(function(resp1, resp2/*, ... */) { // Each argument is an array with the following structure: [ data, statusText, jqXHR ] var responseArgsArray = Array.prototype.slice.call(this, arguments); });
Korzystając ze składni Spread , możesz teraz napisać następujący kod:
$.when(...requests).then((...responses) => { // do something with responses })
Dzieje się tak, ponieważ
$.when
akceptuje takie argumentyA nie tak:
źródło
all
metodę lub coś podobnego, ale podoba mi się koncepcja mapy. Ładny.arguments
zmiennej. Jeśli używasz nowszych funkcji JS, możesz je również przenieść do zmiennej(...args) => {}
.Podoba mi się pomysł hvgotcodes. Proponuję dodać ogólny moduł zwiększający, który porównuje kompletny numer z wymaganym numerem, a następnie uruchamia ostateczne wywołanie zwrotne. Można to wbudować w końcowe wywołanie zwrotne.
var sync = { callbacksToComplete = 3, callbacksCompleted = 0, addCallbackInstance = function(){ this.callbacksCompleted++; if(callbacksCompleted == callbacksToComplete) { doFinalCallBack(); } } };
[Zmieniono, aby odzwierciedlić aktualizacje nazwiska].
źródło
EDYCJA - prawdopodobnie najlepszą opcją byłoby utworzenie punktu końcowego usługi, który wykonuje wszystko, co robią trzy żądania. W ten sposób wystarczy wykonać jedno żądanie, a wszystkie dane znajdują się tam, gdzie są potrzebne w odpowiedzi. Jeśli zauważysz, że wykonujesz te same 3 żądania w kółko, prawdopodobnie będziesz chciał iść tą drogą. Często dobrą decyzją projektową jest skonfigurowanie usługi fasadowej na serwerze, która łączy razem powszechnie używane mniejsze akcje serwera. Tylko pomysł.
Jednym ze sposobów byłoby utworzenie obiektu „sync” w module obsługi kliknięć przed wywołaniami AJAX. Coś jak
var sync = { count: 0 }
Synchronizacja zostanie automatycznie powiązana z zakresem udanych wywołań (zamknięcie). W programie obsługi sukcesu zwiększasz liczbę, a jeśli wynosi 3, możesz wywołać drugą funkcję.
Alternatywnie możesz zrobić coś takiego
var sync = { success1Complete: false, ... success3Complete: false, }
gdy każdy sukces zostanie wykonany, zmieni wartość w synchronizacji na true. Przed kontynuowaniem musisz sprawdzić synchronizację, aby upewnić się, że wszystkie trzy są prawdziwe.
Zwróć uwagę na przypadek, w którym jeden z twoich xhrs nie zwraca sukcesu - musisz to uwzględnić.
Jeszcze inną opcją byłoby zawsze wywołanie ostatniej funkcji w programach obsługujących sukces i udostępnienie jej opcji synchronizacji w celu określenia, czy faktycznie cokolwiek zrobić. Musisz jednak upewnić się, że synchronizacja znajduje się w zakresie tej funkcji.
źródło
Znalazłem łatwiejszy sposób na zrobienie tego bez konieczności stosowania dodatkowych metod porządkujących kolejkę.
JS
$.ajax({ type: 'POST', url: 'ajax1.php', data:{ id: 1, cb:'method1'//declaration of callback method of ajax1.php }, success: function(data){ //catching up values var data = JSON.parse(data); var cb=data[0].cb;//here whe catching up the callback 'method1' eval(cb+"(JSON.stringify(data));");//here we calling method1 and pass all data } }); $.ajax({ type: 'POST', url: 'ajax2.php', data:{ id: 2, cb:'method2'//declaration of callback method of ajax2.php }, success: function(data){ //catching up values var data = JSON.parse(data); var cb=data[0].cb;//here whe catching up the callback 'method2' eval(cb+"(JSON.stringify(data));");//here we calling method2 and pass all data } }); //the callback methods function method1(data){ //here we have our data from ajax1.php alert("method1 called with data="+data); //doing stuff we would only do in method1 //.. } function method2(data){ //here we have our data from ajax2.php alert("method2 called with data="+data); //doing stuff we would only do in method2 //.. }
PHP (ajax1.php)
<?php //catch up callbackmethod $cb=$_POST['cb'];//is 'method1' $json[] = array( "cb" => $cb, "value" => "ajax1" ); //encoding array in JSON format echo json_encode($json); ?>
PHP (ajax2.php)
<?php //catch up callbackmethod $cb=$_POST['cb'];//is 'method2' $json[] = array( "cb" => $cb, "value" => "ajax2" ); //encoding array in JSON format echo json_encode($json); ?>
źródło
Zadałem to samo pytanie jakiś czas temu i otrzymałem tutaj kilka dobrych odpowiedzi: Najlepszy sposób na dodanie `` oddzwonienia '' po serii asynchronicznych wywołań XHR
źródło
Z odpowiedzi na tej stronie mam kilka dobrych wskazówek. Dostosowałem go trochę do swojego użytku i pomyślałem, że mogę się nim podzielić.
// lets say we have 2 ajax functions that needs to be "synchronized". // In other words, we want to know when both are completed. function foo1(callback) { $.ajax({ url: '/echo/html/', success: function(data) { alert('foo1'); callback(); } }); } function foo2(callback) { $.ajax({ url: '/echo/html/', success: function(data) { alert('foo2'); callback(); } }); } // here is my simplified solution ajaxSynchronizer = function() { var funcs = []; var funcsCompleted = 0; var callback; this.add = function(f) { funcs.push(f); } this.synchronizer = function() { funcsCompleted++; if (funcsCompleted == funcs.length) { callback.call(this); } } this.callWhenFinished = function(cb) { callback = cb; for (var i = 0; i < funcs.length; i++) { funcs[i].call(this, this.synchronizer); } } } // this is the function that is called when both ajax calls are completed. afterFunction = function() { alert('All done!'); } // this is how you set it up var synchronizer = new ajaxSynchronizer(); synchronizer.add(foo1); synchronizer.add(foo2); synchronizer.callWhenFinished(afterFunction);
Są tu pewne ograniczenia, ale w moim przypadku było dobrze. Odkryłem również, że dla bardziej zaawansowanych rzeczy jest też wtyczka AOP (dla jQuery), która może być przydatna: http://code.google.com/p/jquery-aop/
źródło
Natknąłem się dziś na ten problem i to była moja naiwna próba przed obejrzeniem zaakceptowanej odpowiedzi.
<script> function main() { var a, b, c var one = function() { if ( a != undefined && b != undefined && c != undefined ) { alert("Ok") } else { alert( "¬¬ ") } } fakeAjaxCall( function() { a = "two" one() } ) fakeAjaxCall( function() { b = "three" one() } ) fakeAjaxCall( function() { c = "four" one() } ) } function fakeAjaxCall( a ) { a() } main() </script>
źródło
To nie jest jquery (i wygląda na to, że jquery ma działające rozwiązanie), ale po prostu inna opcja ....
Miałem podobne problemy podczas intensywnej pracy z usługami internetowymi SharePoint - często trzeba pobierać dane z wielu źródeł, aby wygenerować dane wejściowe dla pojedynczego procesu.
Aby go rozwiązać, osadziłem tego rodzaju funkcjonalność w mojej bibliotece abstrakcji AJAX. Możesz łatwo zdefiniować żądanie, które po zakończeniu wyzwoli zestaw programów obsługi. Jednak każde żądanie można zdefiniować z wieloma wywołaniami HTTP. Oto komponent (i szczegółowa dokumentacja):
DPAJAX w DepressedPress.com
Ten prosty przykład tworzy jedno żądanie z trzema wywołaniami, a następnie przekazuje te informacje w kolejności wywołań do pojedynczego modułu obsługi:
// The handler function function AddUp(Nums) { alert(Nums[1] + Nums[2] + Nums[3]) }; // Create the pool myPool = DP_AJAX.createPool(); // Create the request myRequest = DP_AJAX.createRequest(AddUp); // Add the calls to the request myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [5,10]); myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [4,6]); myRequest.addCall("GET", "http://www.mysite.com/Add.htm", [7,13]); // Add the request to the pool myPool.addRequest(myRequest);
Zauważ, że w przeciwieństwie do wielu innych rozwiązań (w tym uważam, że rozwiązanie „when” w jquery) pod warunkiem, że ta metoda nie wymusza pojedynczego wątku wykonywanych wywołań - każde z nich będzie nadal działać tak szybko (lub tak wolno), jak pozwala na to środowisko ale pojedynczy program obsługi zostanie wywołany tylko wtedy, gdy wszystkie zostaną ukończone. Obsługuje również ustawianie wartości limitu czasu i ponawianie prób, jeśli usługa jest trochę niestabilna.
Uważam, że jest niesamowicie przydatny (i niezwykle łatwy do zrozumienia z punktu widzenia kodu). Koniec z łańcuchem, koniec z liczeniem połączeń i oszczędzaniem wyjścia. Po prostu „ustaw i zapomnij”.
źródło
Ok, to jest stare, ale pozwól mi wnieść moje rozwiązanie :)
function sync( callback ){ syncCount--; if ( syncCount < 1 ) callback(); } function allFinished(){ .............. } window.syncCount = 2; $.ajax({ url: 'url', success: function(data) { sync( allFinished ); } }); someFunctionWithCallback( function(){ sync( allFinished ); } )
Działa również z funkcjami, które mają wywołanie zwrotne. Ustawiasz syncCount i wywołujesz funkcję sync (...) w wywołaniu zwrotnym każdej akcji.
źródło
$.ajax({type:'POST', url:'www.naver.com', dataType:'text', async:false, complete:function(xhr, textStatus){}, error:function(xhr, textStatus){}, success:function( data ){ $.ajax({type:'POST', .... .... success:function(data){ $.ajax({type:'POST', .... .... } } });
Przepraszam, ale nie mogę wyjaśnić, co robię, bo jestem Koreańczykiem, który nie mówi nawet słowa po angielsku. ale myślę, że możesz to łatwo zrozumieć.
źródło
async : false,
Domyślnie wszystkie żądania są wysyłane asynchronicznie (tzn. Domyślnie jest to ustawione na true). Jeśli potrzebujesz synchronicznych żądań, ustaw tę opcję na
false
. Żądania idataType: "jsonp"
żądania między domenami nie obsługują operacji synchronicznych. Należy pamiętać, że żądania synchroniczne mogą tymczasowo blokować przeglądarkę, wyłączając wszelkie działania, gdy żądanie jest aktywne. Począwszy od jQuery 1.8 , używanieasync: false
z jqXHR ($.Deferred
) jest przestarzałe; musisz użyć opcji wywołania zwrotnego sukcesu / błędu / zakończenia zamiast odpowiednich metod obiektu jqXHR, takich jakjqXHR.done()
lub przestarzałyjqXHR.success()
.źródło