2009-07-20 18 views
21

Używam jQuery. I nie chcę równoległych wywołań AJAX w mojej aplikacji, każde wywołanie musi odczekać poprzedni przed rozpoczęciem. Jak to wdrożyć? Jest jakiś pomocnik?Jak wykonać sekwencję połączeń AJAX?

UPDATE Jeśli istnieje jakaś synchroniczna wersja XMLHttpRequest lub jQuery.post Chciałbym wiedzieć. Ale sekwencyjny! = Synchroniczny i chciałbym rozwiązania asynchronicznego i sekwencyjnego.

+4

wiesz co „A” w AJAX stoi, prawda :-) –

+2

to na pewno ja nie ma odpowiedzi, ale jest to ciekawy znak dobrze zaprojektowanego frameworka, gdy * to * jest mylącym pytaniem zamiast tego, jak zrobić to współbieżnie. :) –

+8

@Ed Swangren, tak, ale AJAX nie musi być asynchroniczny, JavaScript ani XML. :-) – Nosredna

Odpowiedz

14

Jest to znacznie lepszy sposób to zrobić niż za pomocą synchronicznych wywołań AJAX. Jquery ajax zwraca odroczone, więc możesz po prostu użyć łańcucha łączenia rur, aby upewnić się, że każde wywołanie ajax zakończy się przed następnymi uruchomieniami. Oto działający przykład z bardziej dogłębnym przykładem: możesz play with on jsfiddle.

// How to force async functions to execute sequentially 
// by using deferred pipe chaining. 

// The master deferred. 
var dfd = $.Deferred(), // Master deferred 
    dfdNext = dfd; // Next deferred in the chain 
    x = 0, // Loop index 
    values = [], 

    // Simulates $.ajax, but with predictable behaviour. 
    // You only need to understand that higher 'value' param 
    // will finish earlier. 
    simulateAjax = function (value) { 
     var dfdAjax = $.Deferred(); 

     setTimeout(
      function() { 
       dfdAjax.resolve(value); 
      }, 
      1000 - (value * 100) 
     ); 

     return dfdAjax.promise(); 
    }, 

    // This would be a user function that makes an ajax request. 
    // In normal code you'd be using $.ajax instead of simulateAjax. 
    requestAjax = function (value) { 
     return simulateAjax(value); 
    }; 

// Start the pipe chain. You should be able to do 
// this anywhere in the program, even 
// at the end,and it should still give the same results. 
dfd.resolve(); 

// Deferred pipe chaining. 
// What you want to note here is that an new 
// ajax call will not start until the previous 
// ajax call is completely finished. 
for (x = 1; x <= 4; x++) { 

    values.push(x); 

    dfdNext = dfdNext.pipe(function() { 
     var value = values.shift(); 
     return requestAjax(value). 
      done(function(response) { 
       // Process the response here. 

      }); 

    }); 

} 

Niektórzy ludzie skomentowali, że nie mają pojęcia, co robi kod. Aby to zrozumieć, najpierw musisz zrozumieć obietnice javascript. Jestem pewien, że obietnice mają wkrótce stać się ojczystym językiem javascript, co powinno dać ci dobrą motywację do nauki.

+0

Hej, to trochę za późno, ale tak czy inaczej: Wielka odpowiedź pomogła mi i działa jak czar. Ale naprawdę nie rozumiem, jak to działa. Próbowałem zrozumieć i czytać dokumenty, ale jest to dla mnie tajemnicą. –

+0

@DanLee Wygląda na to, że nie jesteś jedyny. –

+0

Trudne do zrozumienia obietnice javascript i sposób, w jaki jquery implementuje koncepcję bez uczenia się jej ;-) Mnóstwo dokumentów. –

6

Masz dwie opcje, które mogę wymyślić. Jedną z nich jest połączenie ich za pomocą wywołań zwrotnych. Drugi polega na tym, aby połączenia były synchroniczne, a nie asynchroniczne.

Czy istnieje powód, dla którego chcesz je sekwencyjne? To spowolni sprawę.

Aby połączenie było synchroniczne, ustaw opcję asynchroniczną w wywołaniu Ajax na wartość false. Zobacz dokumentację pod numerem http://docs.jquery.com/Ajax/jQuery.ajax#options (kliknij kartę opcji, aby je zobaczyć).

+0

Jak je synchronizować? –

+0

Lub trzecia opcja: klasa, która zarządzałaby kolejką żądań i przetwarzała je sekwencyjnie. –

+0

Edytowałem swoją odpowiedź, aby wskazać opcje Ajax. Ustaw opcję asynchroniczną na false. – Nosredna

1

Spójrz na to: http://docs.jquery.com/Ajax/jQuery.ajax (kliknij kartę "Opcje").

Pamiętaj jednak, że połączenie synchroniczne zablokuje stronę do czasu otrzymania odpowiedzi, więc nie może być używane w witrynie produkcyjnej, ponieważ użytkownicy będą wściekli, jeśli z jakiegokolwiek powodu będą musieli poczekać 30 sekund z zablokowaną przeglądarką .

EDIT: ok, z aktualizacją jest wyraźniejszy, co chcesz osiągnąć;)

Tak, kod może wyglądać następująco:

$.getJSON("http://example.com/jsoncall", function(data) { 
     process(data); 
     $.getJSON("http://example.com/jsoncall2", function (data) { 
      processAgain(data); 
      $.getJSON("http://example.com/anotherjsoncall", function(data) { 
       processAgainAndAgain(data); 
      }); 
     }); 
    }); 

ten sposób będą wydawane tylko drugie połączenie kiedy odpowiedź na pierwsze połączenie została odebrana i przetworzona, a trzecie połączenie zostanie wydane dopiero po otrzymaniu i przetworzeniu odpowiedzi na drugie połączenie. Ten kod jest dla getJSON, ale może być dostosowany do $ .ajax.

+0

Jestem świadomy twojego rozwiązania, ale wielokrotne żądanie nie jest generowane przez to samo, nawet, więc nie mogę połączyć ich razem, jak pokazałeś.Moje rozwiązanie byłoby bardziej jak blokada (globalAjaxObject) w C# –

1

Najlepszym sposobem na zrobienie tego jest połączenie łańcuchowe, jak powiedział Nosredna. Nie polecam używania synchronicznego XMLHttpRequest, ponieważ blokują one całą twoją aplikację.

Z tego, co wiem, nie ma zbyt wielu pomocników, ale można zrobić coś przypominającego wywołanie zwrotne FIFO.

2

Mogłeś dać narrację javascript spróbować http://www.neilmix.com/narrativejs/doc/

Nigdy go stosować się jednak. Gdybym chciał to zrobić, ustawiłbym jakiś rodzaj abstrakcji do łączenia działań asynchronicznych. Jak powiedzieli inni, synchroniczna wersja obiektu ajax blokuje przetwarzanie zdarzeń podczas oczekiwania na odpowiedź. Powoduje to, że przeglądarka wygląda na zamrożoną, dopóki nie otrzyma odpowiedzi.

+1

To wygląda fajnie. – Nosredna

+0

Dzięki za dodanie, ale nie jestem pewien, czy rozwiązuje mój problem. Wywołuje asynchroniczne wywołania sekwencyjne, jeśli był tylko jeden wątek generujący, ale w moim przypadku wiele zdarzeń spawns rekwizycje. –

+0

Tak jak powiedziałem, nie użyłem NJS, ale jego opis mówi, że dodaje operatora zysku, który po prostu przerywa wykonywanie funkcji, aż do wystrzelenia zdarzenia. Nie wydaje mi się, żeby to zapobiegło współbieżności. Gdyby tak było, nie byłoby to dla nikogo użyteczną biblioteką. – Breton

3

Ustaw opcję asynchroniczny false, np

$.ajax({ async: false /*, your_other_ajax_options_here */ }); 

referencyjny: Ajax/jQuery.ajax

+0

Opcja asynchroniczna zostanie wkrótce usunięta z jQuery. –

+0

To jest najlepsza odpowiedź na pierwotne żądanie OP. Ta sugestia gwarantuje IOE (wykonanie w kolejności) z najmniejszą złożonością. Nigdy nie planowano usunięcia flagi asynchronicznej z jquery, w przeciwieństwie do tego, co sugeruje program @LS. – kamelkev

+1

Pamiętaj: "Od wersji jQuery 1.8 użycie asynchronicznej: false z jqXHR ($ .deferred) jest przestarzałe, należy użyć opcji success/error/complete callback zamiast odpowiednich metod obiektu jqXHR, takich jak jqXHR.done(). " http://docs.jquery.com/Ajax/jQuery.ajax#options –

0

połączenia synchroniczne niekoniecznie są wolniejsze, jeśli masz aplikację gdzie AJAX wywołuje otwarte, stanowisk, następnie zamyka gniazdo, wiele wywołań do gniazda nie ma sensu, ponieważ niektóre gniazda mogą obsługiwać tylko jedno połączenie, w takim przypadku, kolejkowanie danych, więc jego wysyłanie tylko po zakończeniu poprzedniego połączenia AJAX oznacza znacznie większą przepustowość danych.

-1

Co powiesz na temat używania zdarzeń Node.js?

var EventEmitter = require('events').EventEmitter; 
var eventEmitter = new EventEmitter(); 
var $ = require('jquery'); 

var doSomething = function (responseData) { 
    var nextRequestData = {}; 
    // do something with responseData 
    return nextRequestData; 
}; 

// ajax requests 
var request1 = $.ajax; 
var request2 = $.ajax; 
var requests = [request1, request2]; 

eventEmitter.on('next', function (i, requestData) { 
    requests[i](requestData).then(
    function (responseData) { 
     console.log(i, 'request completed'); 
     if (i+1 < requests.length) { 
     var nextRequestData = doSomething(responseData); 
     eventEmitter.emit('next', i+1, nextRequestData); 
     } 
     else { 
     console.log('completed all requests'); 
     } 
    }, 
    function() { 
     console.log(i, 'request failed'); 
    } 
); 
}); 

var data = { 
    //data to send with request 1 
}; 
eventEmitter.emit('next', 0, data); 
0

sekwencyjnego! = Synchroniczne i am asynchroniczny i kolejne rozwiązanie

synchronicznym zazwyczaj oznacza „przy użyciu tego samego zegara”, a ich wykonanie oznacza „w tej kolejności lub sekwencją ".

W przypadku konkretnego przypadku, uważam, że oba warunki muszą zostać spełnione, ponieważ wykonywanie asynchroniczne implikuje możliwość uzyskania niesekwencyjnego wyniku.

0
(async() => { 
    for(f of ['1.json','2.json','3.json']){ 
    var json = await $.getJSON(f); 
    console.log(json) 
}; 
})() 
  1. wnioski 3 pliki json z jQuery AJAX wywołuje
  2. procesu w kolejności (nie równolegle) o czekają
  3. prace w Chrome/Firefox/EDGE (od 1/30/2018)

więcej na MDN

Powiązane problemy