Poczekaj, aż wszystkie żądania Ajax jQuery zostaną wykonane?


675

Jak sprawić, by funkcja czekała, aż wszystkie żądania Ajax jQuery zostaną wykonane w innej funkcji?

Krótko mówiąc, muszę wykonać wszystkie żądania Ajax, zanim wykonam następne. Ale jak?


Jak dzwonisz do swoich oryginalnych żądań ajax?
NakedBrunch

2
Co rozumiesz przez „zrobione”? Rozumiem to jako „wszystkie żądania zostały zakończone pomyślnie lub nie” (rozwiązane lub odrzucone). Ale może to oznaczać „wszystkie żądania zostały pomyślnie zakończone” (rozwiązane). zobacz wszystkie odmiany w api.jquery.com/category/deferred-object
Adrien Be

Odpowiedzi:


911

W tym celu jQuery definiuje teraz funkcję when .

Akceptuje dowolną liczbę Odroczonych obiektów jako argumenty i wykonuje funkcję, gdy wszystkie z nich zostaną rozpoznane.

Oznacza to, że jeśli chcesz zainicjować (na przykład) cztery żądania ajax, a następnie wykonać akcję po ich zakończeniu, możesz zrobić coś takiego:

$.when(ajax1(), ajax2(), ajax3(), ajax4()).done(function(a1, a2, a3, a4){
    // the code here will be executed when all four ajax requests resolve.
    // a1, a2, a3 and a4 are lists of length 3 containing the response text,
    // status, and jqXHR object for each of the four ajax calls respectively.
});

function ajax1() {
    // NOTE:  This function must return the value 
    //        from calling the $.ajax() method.
    return $.ajax({
        url: "someUrl",
        dataType: "json",
        data:  yourJsonData,            
        ...
    });
}

Moim zdaniem zapewnia czystą i przejrzystą składnię i pozwala uniknąć zmiennych globalnych, takich jak ajaxStart i ajaxStop, które mogłyby mieć niepożądane skutki uboczne w miarę rozwoju twojej strony.

Jeśli nie wiesz z góry, na ile argumentów ajax musisz czekać (tzn. Chcesz użyć zmiennej liczby argumentów), możesz to nadal zrobić, ale jest to trochę trudniejsze. Zobacz Przekaż w tablicy Odroczone do $ .when () (i być może jQuery .w przypadku rozwiązywania problemów przy zmiennej liczbie argumentów ).

Jeśli potrzebujesz głębszej kontroli nad trybami błędów skryptów ajax itp., Możesz zapisać zwrócony obiekt .when()- jest to obiekt obietnicy jQuery obejmujący wszystkie oryginalne zapytania ajax. Możesz do niego zadzwonić .then()lub .fail()dodać szczegółowe procedury obsługi sukcesu / niepowodzenia.


46
To powinno być oznaczone jako poprawna odpowiedź, ponieważ jest proste, wydajne i działa świetnie. Należy również zauważyć, że $.whenzwraca Promiseobiekt, który ma nie tylko bardziej użyteczne metody .done. Na przykład za pomocą .then(onSuccess, onFailure)metody można zareagować, gdy oba żądania zakończą się powodzeniem lub co najmniej jedno z nich zakończy się niepowodzeniem.
skalee

2
Czy można spakować żądania ajax1..4 do tablicy i przekazać to?
andig

33
Bądź ostrożny ze failsprawą. W przeciwieństwie do done, failstrzela natychmiast po pierwszej porażce i ignoruje pozostałe odroczenia.
Ryan Mohr

1
@skalee dziękuję za podkreślenie faktu, że onFailuremożna dołączyć funkcję. Jak zauważyłem w komentarzu do pytania PO: może on chcieć bardziej precyzyjnie wskazać, co rozumie przez „zrobione”. „Ryan Mohr” miał również bardzo dobrą opinię na temat tego, że failzachowuje się inaczej, ponieważ donekilka dalszych lektur, które należy zrobić, Promisesto chyba html5rocks.com/en/tutorials/es6/promises
Adrien Be

1
Wspaniale jest dać ludziom kontakt z metodą kiedy i ogólnie obietnicami, ale myślę, że nie jest to najlepsza odpowiedź. Jeśli którakolwiek z tych funkcji ajax gdziekolwiek w dół linii utworzy kolejne żądanie ajax, a następnie nie zintegruje poprawnie tej nowej obietnicy z łańcuchem ... żądania te unikną tej techniki. Na przykład nie mogę użyć tej techniki bez modyfikacji biblioteki Shopify, której używam do działania dodawania do koszyka ajax, ponieważ nie została napisana w sposób „obiecujący” i nigdy nie zwraca utworzonych obiektów xhr. Czy to ma sens? Nadal świetna odpowiedź!
Ziggy,

292

Jeśli chcesz wiedzieć, kiedy wszystkie ajax żądania zostaną zakończone w twoim dokumencie, bez względu na to, ile ich istnieje, po prostu użyj zdarzenia $ .ajaxStop w ten sposób:

$(document).ajaxStop(function () {
  // 0 === $.active
});

W takim przypadku nie musisz zgadywać, ile żądań dzieje się w aplikacji, które mogą zakończyć się w przyszłości, ani nie zagłębić się w skomplikowaną logikę funkcji lub znaleźć, które funkcje wykonują HTTP(S)żądania.

$.ajaxStoptutaj można również powiązać z dowolnym HTMLwęzłem, który Twoim zdaniem może zostać zmodyfikowany przez żądanie.


Aktualizacja:
jeśli chcesz trzymać się ESskładni, możesz użyć Promise.all dla znanych ajaxmetod:

Promise.all([ajax1(), ajax2()]).then(() => {
  // all requests finished successfully
}).catch(() => {
  // all requests finished but one or more failed
})

Interesującym punktem jest to, że działa zarówno z, jak Promisesi $.ajaxżądaniami.

Oto demonstracja jsFiddle .


Aktualizacja 2:
Jeszcze nowsza wersja wykorzystująca składnię asynchroniczną / oczekującą :

try {
  const results = await Promise.all([ajax1(), ajax2()])
  // do other actions
} catch(ex) { }

16
+1 Znacznie lepiej niż inne odpowiedzi w przypadku , gdy masz do czynienia ze skryptami innych firm z anonimowymi wywołaniami zwrotnymi / zamknięciami.
kaiser

5
@kaiser Ważny punkt, ale nie o to pytało pytanie. Nie jest to zbyt dobre, jeśli nie chcesz czekać na wszystkie wywołania AJAX. Pytanie dotyczy oczekiwania na wywołania AJAX, które wykonałeś samodzielnie (wywołane wewnątrz innej funkcji, jak napisał OP). Inny kod mógł wykonać inne wywołanie AJAX, na które nie chcesz czekać.
Juan Mendes

6
W porównaniu do rozwiązania when () ma tę zaletę, że działa nawet wtedy, gdy liczba wywołań ajax nie jest znana.
Alexis Dufrenoy,

5
W porównaniu z rozwiązaniem when () ma tę wadę, że nie współpracuje dobrze z innymi komponentami, ponieważ dzieli stan globalny obejmujący cały dokument. Jeśli trwa ciągłe odpytywanie, może nawet nigdy nie odpalić.
Bergi

3
Nie masz racji @AdrienBe, ajaxStop obsługuje wszystkie żądania ajax bez względu na to, czy im się uda, czy nie, tak jak dowód moich słów, spójrz na to jsfiddle.net/36votxba/2
Arsen Khachaturyan

32

Znalazłem dobrą odpowiedź od gnarfa, której właśnie szukałem :)

jQuery ajaxQueue

//This handles the queues    
(function($) {

  var ajaxQueue = $({});

  $.ajaxQueue = function(ajaxOpts) {

    var oldComplete = ajaxOpts.complete;

    ajaxQueue.queue(function(next) {

      ajaxOpts.complete = function() {
        if (oldComplete) oldComplete.apply(this, arguments);

        next();
      };

      $.ajax(ajaxOpts);
    });
  };

})(jQuery);

Następnie możesz dodać do kolejki zapytanie ajax w następujący sposób:

$.ajaxQueue({
        url: 'page.php',
        data: {id: 1},
        type: 'POST',
        success: function(data) {
            $('#status').html(data);
        }
    });

37
Wygląda na to, że zapomniałeś właściwie przypisać tę odpowiedź , dodałem ją.
Tim Post

21

Wykorzystaj ajaxStopwydarzenie.

Załóżmy na przykład, że masz komunikat ładujący ... podczas pobierania 100 żądań ajax i chcesz ukryć tę wiadomość po załadowaniu.

Z dokumentu jQuery :

$("#loading").ajaxStop(function() {
  $(this).hide();
});

Pamiętaj, że będzie czekać na wszystkie żądania ajax wykonane na tej stronie.


5
Zakłada się, że wiesz, że na stronie nie będzie żadnych innych żądań AJAX, niezbyt dobre założenie
Juan Mendes

Począwszy od jQuery 1.8, metoda .ajaxStop () powinna być dołączana tylko do dokumentu.
Geomorillo,

1
Popraw mnie, jeśli się mylę, ale czy to nie zmieni twojego projektu w stronę „oldschoolowych formularzy internetowych”? Mam na myśli to, że jeśli cała strona musi czekać na żądanie, zanim będzie mogło być kontynuowane, jaki jest sens żądania ajax?
BillRuhl

@BillRuhl w naszym przypadku przeglądam kolekcję jquery, aby tworzyć nowe rzeczy i muszę wiedzieć o całej kolekcji po jej zakończeniu, zanim wprowadzę pewne zmiany w układzie. Nie wydaje się to szczególnie niezwykłym przypadkiem. Byłoby źle, gdyby kilka innych rzeczy ajax mogło być w toku, ale tutaj nie będzie.
eon

21

UWAGA: Powyższe odpowiedzi wykorzystują funkcjonalność, która nie istniała w chwili pisania tej odpowiedzi. Zalecam stosowanie jQuery.when()zamiast tych metod, ale pozostawiam odpowiedź do celów historycznych.

-

Prawdopodobnie możesz sobie poradzić z prostym semaforem liczącym, chociaż sposób jego implementacji będzie zależał od twojego kodu. Prostym przykładem byłoby coś takiego ...

var semaphore  = 0,     // counting semaphore for ajax requests
    all_queued = false; // bool indicator to account for instances where the first request might finish before the second even starts

semaphore++;
$.get('ajax/test1.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test2.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test3.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

semaphore++;
$.get('ajax/test4.html', function(data) {
    semaphore--;
    if (all_queued && semaphore === 0) {
        // process your custom stuff here
    }
});

// now that all ajax requests are queued up, switch the bool to indicate it
all_queued = true;

Jeśli chcesz, aby działało to jak {async: false}, ale nie chciałeś blokować przeglądarki, możesz to samo zrobić z kolejką jQuery.

var $queue = $("<div/>");
$queue.queue(function(){
    $.get('ajax/test1.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test2.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test3.html', function(data) {
        $queue.dequeue();
    });
}).queue(function(){
    $.get('ajax/test4.html', function(data) {
        $queue.dequeue();
    });
});

10
Wydaje się, że nadmiernie skomplikowałoby to trywialny problem.
Chris

2
To naprawdę nie jest takie skomplikowane. Liczenie semaforów jest powszechnym mechanizmem w CS. Jeśli wolisz, przykład z kolejkami jQuery również działałby bez konieczności samodzielnego wdrażania semafora.
BBonifield,

1
Nie widzę problemu z licznikiem semaforów, jednak widzę problem z pomysłem posiadania CZTERECH funkcji do obsługi wynikowego wywołania zwrotnego. Powinieneś najpierw zdefiniować funkcję, a następnie odwołać się do tej funkcji w każdej z nich .get(). W ten sposób przynajmniej nie powielasz tego kodu. Nie tylko to, ale deklarowanie za function(){}każdym razem przydziela pamięć za każdym razem! Raczej zła praktyka, jeśli można wywołać funkcję zdefiniowaną statycznie.
Alexis Wilke,

1
@AlexisWilke To jest 4,5-letnia odpowiedź, która miała być przykładem działania semaforów i kolejek. Myślisz o tym trochę za mocno i nie sądzę, aby KAPITALIZACJA BYŁA PUNKTEM jest konieczna.
BBonifield

2
Cóż ... Nie jestem tym, który dał ci -1 ... i rozumiem, że odpowiedzi zwykle się starzeją. Jednak ludzie wciąż je znajdują i o ile wiem, nie jest zabronione przekazywanie informacji osobom, które potencjalnie będą z nich korzystać jeszcze dziś.
Alexis Wilke

8

javascript jest oparty na zdarzeniach, więc nigdy nie powinieneś czekać , raczej ustaw haki / callbacki

Prawdopodobnie możesz po prostu użyć powodzenia / kompletnych metod jquery.ajax

Lub możesz użyć .ajaxComplete :

$('.log').ajaxComplete(function(e, xhr, settings) {
  if (settings.url == 'ajax/test.html') {
    $(this).text('Triggered ajaxComplete handler.');
    //and you can do whatever other processing here, including calling another function...
  }
});

chociaż powinieneś opublikować pseudokod, w jaki sposób twoje (a) żądania (a) ajaxowe są (są) wywoływane, aby być bardziej precyzyjnym ...


8

Trochę tego obejścia:

// Define how many Ajax calls must be done
var ajaxCalls = 3;
var counter = 0;
var ajaxCallComplete = function() {
    counter++;
    if( counter >= ajaxCalls ) {
            // When all ajax calls has been done
        // Do something like hide waiting images, or any else function call
        $('*').css('cursor', 'auto');
    }
};

var loadPersons = function() {
        // Show waiting image, or something else
    $('*').css('cursor', 'wait');

    var url = global.ctx + '/loadPersons';
    $.getJSON(url, function(data) {
            // Fun things
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCountries = function() {
    // Do things
    var url = global.ctx + '/loadCountries';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

var loadCities = function() {
    // Do things
    var url = global.ctx + '/loadCities';
    $.getJSON(url, function(data) {
            // Travels
    })
    .complete(function() { **ajaxCallComplete();** });
};

$(document).ready(function(){
    loadPersons();
    loadCountries();
    loadCities();
});

Nadzieja może się przydać ...


Podczas gdy pozostałe odpowiedzi są technicznie lepsze, ponieważ są łatwiejsze do zrozumienia, naprawdę podoba mi się ta. Miły!
Jay

4

jQuery pozwala określić, czy chcesz, aby żądanie ajax było asynchroniczne, czy nie. Możesz po prostu zsynchronizować żądania ajax, a wtedy reszta kodu nie zostanie wykonana, dopóki nie zostaną zwrócone.

Na przykład:

jQuery.ajax({ 
    async: false,
    //code
});

42
Należy zauważyć, że użycie {async: false} może tymczasowo zablokować przeglądarkę. api.jquery.com/jQuery.ajax
BBonifield

30
Jest to sprzeczne ze standardową praktyką jQuery / JavaScript. AJAX zawsze powinien być asynchroniczny. Zamiast tego powinieneś użyć jQuery.when ().
SystemParadox

43
To okropnie zły pomysł! Nigdy tego nie rób! Blokowanie = brak reakcji na działania użytkownika, nawet na przewijanie lub cokolwiek innego! (Również async: false będzie przestarzałe w jQuery 1.8.)
skalee

5
W szczególności, jeśli żądanie nie powiedzie się lub zajmie dużo czasu z jakiegoś nieprzewidywalnego powodu (który zgodnie z prawem Murphy'ego musi się wydarzyć!), Jest to zwykle zły pomysł na kod produkcyjny z powodu blokowania przeglądarki, jak wspomniano powyżej.
Alex

27
To okropnie zły pomysł. NIE UŻYWAJ TEJ ODPOWIEDZI.
Tauren

2

Jeśli potrzebujesz czegoś prostego; raz i gotowe oddzwonienie

        //multiple ajax calls above
        var callback = function () {
            if ($.active !== 0) {
                setTimeout(callback, '500');
                return;
            }
            //whatever you need to do here
            //...
        };
        callback();

4
może generować nieskończoną pętlę!
Diego Favero

2
To jest nieskończona pętla? Kiedy? Kiedy AJAX nigdy nie powraca?
Jonathan

2

Możesz także użyć async.js .

Myślę, że jest lepszy niż $ .when, ponieważ można scalić wszystkie rodzaje wywołań asynchronicznych, które nie obsługują obietnic po wyjęciu z pudełka, takich jak limity czasu, wywołania SqlLite itp., A nie tylko żądania ajax.


2

Na podstawie odpowiedzi @BBonifield napisałem funkcję narzędzia, dzięki której logika semaforów nie rozprzestrzenia się we wszystkich wywołaniach ajax.

untilAjax to funkcja narzędziowa, która wywołuje funkcję zwrotną po zakończeniu wszystkich wywołań ajaxCall.

ajaxObjsjest tablicą obiektów ustawień ajax [http://api.jquery.com/jQuery.ajax/].

fn jest funkcją oddzwaniania

function untilAjax(ajaxObjs, fn) {
  if (!ajaxObjs || !fn) {
    return;
  }
  var ajaxCount = ajaxObjs.length,
    succ = null;

  for (var i = 0; i < ajaxObjs.length; i++) { //append logic to invoke callback function once all the ajax calls are completed, in success handler.
    succ = ajaxObjs[i]['success'];
    ajaxObjs[i]['success'] = function(data) { //modified success handler
      if (succ) {
        succ(data);
      }
      ajaxCount--;
      if (ajaxCount == 0) {
        fn(); //modify statement suitably if you want 'this' keyword to refer to another object
      }
    };
    $.ajax(ajaxObjs[i]); //make ajax call
    succ = null;
  };

Przykład: doSomethingzastosowania funkcji untilAjax.

function doSomething() {
  // variable declarations
  untilAjax([{
    url: 'url2',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url1',
    dataType: 'json',
    success: function(data) {
      //do something with success data
    }
  }, {
    url: 'url2',
    dataType: 'json',
    success: function(response) {
      //do something with success data
    }
  }], function() {
    // logic after all the calls are completed.
  });
}

2

Zdecydowanie polecam użycie $ .when (), jeśli zaczynasz od zera.

Mimo że to pytanie ma ponad milion odpowiedzi, nadal nie znalazłem nic przydatnego w mojej sprawie. Powiedzmy, że masz do czynienia z istniejącą bazą kodów, już wykonując kilka wywołań ajax i nie chcesz wprowadzać złożoności obietnic i / lub przerobić całą sprawę.

Możemy łatwo wykorzystać jQuery .data, .ona .triggerfunkcje, które były częścią jQuery od zawsze.

Codepen

Dobra rzecz w moim rozwiązaniu to:

  • oczywiste jest, na czym dokładnie zależy oddzwonienie

  • funkcja triggerNowOrOnLoadednie dba o to, czy dane zostały już załadowane, czy nadal na nie czekamy

  • bardzo łatwo jest podłączyć go do istniejącego kodu

$(function() {

  // wait for posts to be loaded
  triggerNowOrOnLoaded("posts", function() {
    var $body = $("body");
    var posts = $body.data("posts");

    $body.append("<div>Posts: " + posts.length + "</div>");
  });


  // some ajax requests
  $.getJSON("https://jsonplaceholder.typicode.com/posts", function(data) {
    $("body").data("posts", data).trigger("posts");
  });

  // doesn't matter if the `triggerNowOrOnLoaded` is called after or before the actual requests 
  $.getJSON("https://jsonplaceholder.typicode.com/users", function(data) {
    $("body").data("users", data).trigger("users");
  });


  // wait for both types
  triggerNowOrOnLoaded(["posts", "users"], function() {
    var $body = $("body");
    var posts = $body.data("posts");
    var users = $body.data("users");

    $body.append("<div>Posts: " + posts.length + " and Users: " + users.length + "</div>");
  });

  // works even if everything has already loaded!
  setTimeout(function() {

    // triggers immediately since users have been already loaded
    triggerNowOrOnLoaded("users", function() {
      var $body = $("body");
      var users = $body.data("users");

      $body.append("<div>Delayed Users: " + users.length + "</div>");
    });

  }, 2000); // 2 seconds

});

// helper function
function triggerNowOrOnLoaded(types, callback) {
  types = $.isArray(types) ? types : [types];

  var $body = $("body");

  var waitForTypes = [];
  $.each(types, function(i, type) {

    if (typeof $body.data(type) === 'undefined') {
      waitForTypes.push(type);
    }
  });

  var isDataReady = waitForTypes.length === 0;
  if (isDataReady) {
    callback();
    return;
  }

  // wait for the last type and run this function again for the rest of the types
  var waitFor = waitForTypes.pop();
  $body.on(waitFor, function() {
    // remove event handler - we only want the stuff triggered once
    $body.off(waitFor);

    triggerNowOrOnLoaded(waitForTypes, callback);
  });
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>Hi!</body>


2

Używam sprawdzania rozmiaru po zakończeniu ładowania całego ajax

function get_ajax(link, data, callback) {
    $.ajax({
        url: link,
        type: "GET",
        data: data,
        dataType: "json",
        success: function (data, status, jqXHR) {
            callback(jqXHR.status, data)
        },
        error: function (jqXHR, status, err) {
            callback(jqXHR.status, jqXHR);
        },
        complete: function (jqXHR, status) {
        }
    })
}

function run_list_ajax(callback){
    var size=0;
    var max= 10;
    for (let index = 0; index < max; index++) {
        var link = 'http://api.jquery.com/ajaxStop/';
        var data={i:index}
        get_ajax(link,data,function(status, data){
            console.log(index)
            if(size>max-2){
                callback('done')
            }
            size++
            
        })
    }
}

run_list_ajax(function(info){
    console.log(info)
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>


kciuki do twojego przykładu.
MarwaAhmad

2

Aby rozwinąć odpowiedź Alexa, mam przykład ze zmiennymi argumentami i obietnicami. Chciałem załadować obrazy za pośrednictwem ajax i wyświetlić je na stronie po ich załadowaniu.

Aby to zrobić, użyłem następującego:

let urlCreator = window.URL || window.webkitURL;

// Helper function for making ajax requests
let fetch = function(url) {
    return $.ajax({
        type: "get",
        xhrFields: {
            responseType: "blob"
        },
        url: url,
    });
};

// Map the array of urls to an array of ajax requests
let urls = ["https://placekitten.com/200/250", "https://placekitten.com/300/250"];
let files = urls.map(url => fetch(url));

// Use the spread operator to wait for all requests
$.when(...files).then(function() {
    // If we have multiple urls, then loop through
    if(urls.length > 1) {
        // Create image urls and tags for each result
        Array.from(arguments).forEach(data => {
            let imageUrl = urlCreator.createObjectURL(data[0]);
            let img = `<img src=${imageUrl}>`;
            $("#image_container").append(img);
        });
    }
    else {
        // Create image source and tag for result
        let imageUrl = urlCreator.createObjectURL(arguments[0]);
        let img = `<img src=${imageUrl}>`;
        $("#image_container").append(img);
    }
});

Zaktualizowany do pracy z jednym lub wieloma adresami URL: https://jsfiddle.net/euypj5w9/


2

Jak wspomniano w innych odpowiedziach, możesz ajaxStop()poczekać, aż wszystkie żądania ajax zostaną zakończone.

$(document).ajaxStop(function() {
     // This function will be triggered every time any ajax request is requested and completed
});

Jeśli chcesz to zrobić dla konkretnego ajax()żądania, najlepiej możesz użyć complete()metody wewnątrz określonego żądania ajax:

$.ajax({
    type: "POST",
    url: "someUrl",
    success: function(data) {
        // This function will be triggered when ajax returns a 200 status code (success)
    },
    complete: function() {
        // This function will be triggered always, when ajax request is completed, even it fails/returns other status code
    },
    error: function() {
        // This will be triggered when ajax request fail.
    }
});


Ale jeśli musisz poczekać tylko na kilka i pewne żądania ajax, które mają zostać wykonane? Skorzystaj ze wspaniałych obietnic javascript, aby poczekać, aż te aukcje, na które chcesz czekać, zostaną zakończone. Zrobiłem krótki, łatwy i czytelny przykład, aby pokazać, jak obietnice działają z ajaxem.
Proszę spojrzeć na następny przykład . Użyłem setTimeoutdo wyjaśnienia przykład.

// Note:
// resolve() is used to mark the promise as resolved
// reject() is used to mark the promise as rejected

$(document).ready(function() {
    $("button").on("click", function() {

        var ajax1 = new Promise((resolve, reject) => {
            $.ajax({
                type: "GET",
                url: "https://miro.medium.com/max/1200/0*UEtwA2ask7vQYW06.png",
                xhrFields: { responseType: 'blob'},
                success: function(data) {
                    setTimeout(function() {
                        $('#image1').attr("src", window.URL.createObjectURL(data));
                        resolve(" Promise ajax1 resolved");
                    }, 1000);
                },
                error: function() {
                    reject(" Promise ajax1 rejected");
                },
            });
        });

        var ajax2 = new Promise((resolve, reject) => {
            $.ajax({
                type: "GET",
                url: "https://cdn1.iconfinder.com/data/icons/social-media-vol-1-1/24/_github-512.png",
                xhrFields: { responseType: 'blob' },
                success: function(data) {
                    setTimeout(function() {
                         $('#image2').attr("src", window.URL.createObjectURL(data));
                         resolve(" Promise ajax2 resolved");
                    }, 1500);
                },
                error: function() {
                    reject(" Promise ajax2 rejected");
                },
            });
        });

        var ajax3 = new Promise((resolve, reject) => {
            $.ajax({
                type: "GET",
                url: "https://miro.medium.com/max/632/1*LUfpOf7teWvPdIPTBmYciA.png",
                xhrFields: { responseType: 'blob' },
                success: function(data) {
                    setTimeout(function() {
                         $('#image3').attr("src", window.URL.createObjectURL(data));
                         resolve(" Promise ajax3 resolved");
                    }, 2000);
                },
                error: function() {
                    reject(" Promise ajax3 rejected");
                },
            });
        });
        
        Promise.all([ajax1, ajax2, ajax3]).then(values => {
            console.log("We waited until ajax ended: " + values);
            console.log("My few ajax ended, lets do some things!!")
        }, reason => {
            console.log("Promises failed: " + reason);
        });
        
        // Or if you want wait for them individually do it like this
        // ajax1.then(values => {
        //    console.log("Promise 1 resolved: " + values)
        // }, reason => {
        //     console.log("Promise 1 failed: " + reason)
        // });
    });

});
img {
  max-width: 200px;
  max-height: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Make AJAX request</button>
<div id="newContent">
    <img id="image1" src="">
    <img id="image2" src="">
    <img id="image3" src="">
</div>


0

Znalazłem prosty sposób, używając shift()

function waitReq(id)
{
  jQuery.ajax(
  {
    type: 'POST',
    url: ajaxurl,
    data:
    {
      "page": id
    },
    success: function(resp)
    {
      ...........
      // check array length if not "0" continue to use next array value
      if(ids.length)
      {
        waitReq(ids.shift()); // 2
      )
    },
    error: function(resp)
    {
      ....................
      if(ids.length)
      {
        waitReq(ids.shift());
      )
    }
  });
}

var ids = [1, 2, 3, 4, 5];    
// shift() = delete first array value (then print)
waitReq(ids.shift()); // print 1

0

Moje rozwiązanie jest następujące

var request;
...
'services': {
  'GetAddressBookData': function() {
    //This is the primary service that loads all addressbook records 
    request = $.ajax({
      type: "POST",
      url: "Default.aspx/GetAddressBook",
      contentType: "application/json;",
      dataType: "json"
    });
  },

  ...

  'apps': {
    'AddressBook': {
      'data': "",
      'Start': function() {
          ...services.GetAddressBookData();
          request.done(function(response) {
            trace("ajax successful");
            ..apps.AddressBook.data = response['d'];
            ...apps.AddressBook.Filter();
          });
          request.fail(function(xhr, textStatus, errorThrown) {
            trace("ajax failed - " + errorThrown);
          });

Działało całkiem nieźle. Próbowałem wielu różnych sposobów na zrobienie tego, ale okazało się, że jest to najprostszy i najbardziej wielokrotnego użytku. Mam nadzieję, że to pomoże


0

Spójrz na moje rozwiązanie:

1.Włóż tę funkcję (i zmienną) do pliku javascript:

var runFunctionQueue_callback;

function runFunctionQueue(f, index, callback) {

  var next_index = index + 1

  if (callback !== undefined) runFunctionQueue_callback = callback;

  if (f[next_index] !== undefined) {
    console.log(index + ' Next function avalaible -> ' + next_index);
    $.ajax({
      type: 'GET',
      url: f[index].file,
      data: (f[index].data),
      complete: function() {
        runFunctionQueue(f, next_index);
      }
    });
  } else {
    console.log(index + ' Last function');
    $.ajax({
      type: 'GET',
      url: f[index].file,
      data: (f[index].data),
      async: false,
      complete: runFunctionQueue_callback
    });
  }
}

2.Zbuduj tablicę ze swoimi żądaniami:

var f = [
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}},
           {file: 'file_path', data: {action: 'action', data: 'any_data}}
        ];

3. Utwórz funkcję oddzwaniania:

function Function_callback() {
  alert('done');
}

4. Wywołaj funkcję runFunctionQueue z parametrami:

runFunctionQueue(f, 0, QuestionInsert_callback);
// first parameter: array with requests data
// second parameter: start from first request
// third parameter: the callback function


-4

Wypróbuj w ten sposób utwórz pętlę wewnątrz funkcji skryptu Java, aby poczekać, aż zakończy się wywołanie ajax.

function getLabelById(id)
{
    var label = '';
    var done = false;
    $.ajax({
       cache: false,
       url: "YourMvcActionUrl",
       type: "GET",
       dataType: "json",
       async: false,
       error: function (result) {
         label='undefined';
         done = true;
        },
       success: function (result) {
            label = result.Message;
            done = true;
        }
     });

   //A loop to check done if ajax call is done.
   while (!done)
   {
      setTimeout(function(){ },500); // take a sleep.
   }

    return label;
}

1
Twój setTimeout()NIE take a sleep. W takim przypadku po prostu blokujesz wszystkie karty, aż stanie donesię prawdą.
Alexis Wilke,

1
Myślę, że to jest ten temat z pytaniem: „Poczekaj, aż wszystkie żądania jQuery Ajax zostaną wykonane”.
ChinaHelloWorld

1
Czy przetestowałeś ten kod? oczekuję, że donenigdy nie będzie to prawdą, dopóki pętla while będzie nadal działać. Jeśli pętla while jest uruchomiona, pętla zdarzeń nie może być kontynuowana i dlatego nigdy nie uruchomi wywołania zwrotnego do sukcesu ajax.
Kevin B,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.