Đợi cho đến khi tất cả các yêu cầu jQuery Ajax được thực hiện?


675

Làm cách nào để tạo một hàm chờ cho đến khi tất cả các yêu cầu jQuery Ajax được thực hiện bên trong một hàm khác?

Nói tóm lại, tôi cần đợi tất cả các yêu cầu Ajax được thực hiện trước khi tôi thực hiện tiếp theo. Nhưng bằng cách nào?


Làm thế nào bạn gọi các yêu cầu ajax ban đầu của bạn?
NakedBrunch

2
"Làm" nghĩa là gì? Tôi hiểu nó là "tất cả các yêu cầu đã kết thúc thành công hoặc không" (đã giải quyết hoặc từ chối). Nhưng bạn có thể có nghĩa là "tất cả các yêu cầu đã kết thúc thành công" (đã giải quyết). xem tất cả các biến thể trong api.jquery.com/carget/deferred-object
Adrien Be

Câu trả lời:


911

Bây giờ jQuery định nghĩa một hàm khi cho mục đích này.

Nó chấp nhận bất kỳ số lượng đối tượng Trì hoãn nào làm đối số và thực thi một hàm khi tất cả chúng giải quyết.

Điều đó có nghĩa là, nếu bạn muốn bắt đầu (ví dụ) bốn yêu cầu ajax, sau đó thực hiện một hành động khi chúng được thực hiện, bạn có thể làm một cái gì đó như thế này:

$.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,            
        ...
    });
}

Theo tôi, nó tạo ra một cú pháp rõ ràng và rõ ràng và tránh liên quan đến bất kỳ biến toàn cục nào như ajaxStart và ajaxStop, có thể có tác dụng phụ không mong muốn khi trang của bạn phát triển.

Nếu bạn không biết trước có bao nhiêu đối số ajax bạn cần chờ (nghĩa là bạn muốn sử dụng một số lượng đối số khác nhau), thì vẫn có thể thực hiện được nhưng chỉ cần một chút khó khăn hơn. Xem Pass trong một mảng của Trì hoãn đến $ .when () (và có thể jQuery .when xử lý sự cố với số lượng đối số thay đổi ).

Nếu bạn cần kiểm soát sâu hơn các chế độ thất bại của các tập lệnh ajax, v.v., bạn có thể lưu đối tượng được trả về bởi .when()- đó là một đối tượng Promise jQuery bao gồm tất cả các truy vấn ajax ban đầu. Bạn có thể gọi .then()hoặc .fail()trên đó để thêm các trình xử lý thành công / thất bại chi tiết.


46
Điều này nên được đánh dấu là một câu trả lời đúng bởi vì nó đơn giản, hiệu quả và hoạt động tuyệt vời. Ngoài ra, cần lưu ý rằng $.whentrả về một Promiseđối tượng có các phương thức hữu ích hơn, không chỉ .done. Ví dụ: với .then(onSuccess, onFailure)phương pháp bạn có thể phản ứng khi cả hai yêu cầu thành công hoặc ít nhất một trong số chúng không thành công.
skalee

2
Có thể gộp các yêu cầu ajax1..4 thành một mảng và truyền nó không?
andig

33
Hãy cẩn thận với failtrường hợp. Không giống như done, failbắn ngay lập tức vào lần thất bại đầu tiên và coi thường những người trì hoãn còn lại.
Ryan Mohr

1
@skalee cảm ơn vì đã nhấn mạnh thực tế là một onFailurechức năng có thể được đính kèm. Như tôi đã chỉ ra trong một bình luận cho câu hỏi của OP: anh ta có thể muốn chỉ ra chính xác hơn những gì anh ta có nghĩa là "thực hiện". "Ryan Mohr" cũng đã có một điểm rất tốt về thực tế là failxử lý khác nhau như done, một số đọc thêm việc phải làm về Promisestôi đoán html5rocks.com/en/tutorials/es6/promises
Adrien Be

1
Thật tuyệt khi cho mọi người tiếp xúc với phương pháp khi và nói chung, nhưng tôi nghĩ đây không phải là câu trả lời hay nhất. Nếu bất kỳ chức năng ajax nào ở bất kỳ đâu trong dòng tạo ra một yêu cầu ajax khác, và sau đó không tích hợp lời hứa mới đó vào chuỗi một cách chính xác ... những yêu cầu đó sẽ thoát khỏi kỹ thuật này. Ví dụ: tôi không thể sử dụng kỹ thuật này mà không sửa đổi thư viện Shopify tôi đang sử dụng cho hành vi bổ sung ajax, bởi vì nó không được viết theo cách 'quảng cáo' và không bao giờ trả về các đối tượng xhr mà nó tạo ra. Điều này có nghĩa không? Vẫn là một câu trả lời tuyệt vời!
Ziggy

292

Nếu bạn muốn biết khi nào tất cả các ajax yêu cầu kết thúc trong tài liệu của bạn, bất kể có bao nhiêu trong số chúng tồn tại, chỉ cần sử dụng sự kiện $ .ajaxStop theo cách này:

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

Trong trường hợp này, bạn không cần phải đoán có bao nhiêu yêu cầu đang xảy ra trong ứng dụng, có thể kết thúc trong tương lai, cũng không đào sâu vào các hàm logic phức tạp hoặc tìm chức năng nào đang thực hiện HTTP(S)yêu cầu.

$.ajaxStopở đây cũng có thể được liên kết với bất kỳ HTMLnút nào mà bạn nghĩ có thể được sửa đổi bởi requst.


Cập nhật:
Nếu bạn muốn ESsử dụng cú pháp, thì bạn có thể sử dụng Promise.all cho ajaxcác phương thức đã biết :

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

Một điểm thú vị ở đây là nó hoạt động cả với Promises$.ajax yêu cầu.

Dưới đây là trình diễn jsFiddle .


Cập nhật 2:
Phiên bản mới hơn sử dụng cú pháp async / await :

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

16
+1 Tốt hơn nhiều so với các câu trả lời khác trong trường hợp bạn phải xử lý các tập lệnh của bên thứ 3 với các cuộc gọi lại / đóng cửa ẩn danh.
kaiser

5
@kaiser Điểm hợp lệ nhưng đó không phải là câu hỏi. Sẽ không tốt lắm nếu bạn không muốn đợi tất cả các cuộc gọi AJAX trở lại. Câu hỏi cụ thể về việc chờ đợi các cuộc gọi AJAX mà bạn tự thực hiện (được gọi bên trong một chức năng khác, như OP đã viết). Một số mã khác có thể đã thực hiện một cuộc gọi AJAX khác mà bạn không muốn chờ đợi.
Juan Mendes

6
So với giải pháp khi (), nó có lợi thế để hoạt động ngay cả khi không biết số lượng cuộc gọi ajax.
Alexis Dufrenoy

5
So với giải pháp khi (), nó có nhược điểm lớn là không hoạt động tốt với các thành phần khác, vì nó chia sẻ trạng thái toàn cầu trên toàn tài liệu. Nếu có một cuộc bỏ phiếu dài diễn ra liên tục, nó thậm chí có thể không bao giờ cháy.
Bergi

3
Bạn không phải là đúng @AdrienBe, ajaxStop xử lý tất cả các yêu cầu ajax dù sao họ thành công hay không, chỉ cần làm bằng chứng lời nói của tôi xem xét điều này jsfiddle.net/36votxba/2
Arsen Khachaturyan

32

Tôi đã tìm thấy một câu trả lời tốt bằng cách gnarf bản thân mình, đó chính xác là những gì tôi đang tìm kiếm :)

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);

Sau đó, bạn có thể thêm yêu cầu ajax vào hàng đợi như thế này:

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

37
Có vẻ như bạn đã quên đưa ra sự quy kết thích hợp cho câu trả lời này , tôi đã thêm nó.
Tim Post

21

Sử dụng ajaxStopsự kiện.

Ví dụ: giả sử bạn có tải ... tin nhắn trong khi tìm nạp 100 yêu cầu ajax và bạn muốn ẩn tin nhắn đó sau khi tải.

Từ tài liệu jQuery :

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

Xin lưu ý rằng nó sẽ đợi tất cả các yêu cầu ajax được thực hiện trên trang đó.


5
Điều này giả định rằng bạn biết sẽ không có bất kỳ yêu cầu AJAX nào khác trên trang, không phải là một giả định rất tốt
Juan Mendes

Kể từ jQuery 1.8, phương thức .ajaxStop () chỉ nên được đính kèm vào tài liệu.
Geomorillo

1
Chỉnh sửa cho tôi nếu tôi sai nhưng điều này sẽ không biến dự án của bạn thành một trang web "biểu mẫu web trường học cũ" chứ? Ý tôi là nếu toàn bộ trang của bạn phải đợi một yêu cầu trước khi nó có thể tiếp tục thì điểm của yêu cầu ajax ở nơi đầu tiên là gì?
BillRuhl

@BillRuhl trong trường hợp của chúng tôi, tôi đang lặp qua bộ sưu tập jquery để xây dựng công cụ mới và cần biết về toàn bộ bộ sưu tập khi hoàn thành, trước khi thực hiện một số điều chỉnh bố cục. Có vẻ như không phải là một trường hợp đặc biệt. Sẽ rất tệ nếu một loạt các công cụ ajax khác có thể đang được xử lý, nhưng nó sẽ không ở đây.
eon

21

LƯU Ý: Các câu trả lời trên sử dụng chức năng không tồn tại tại thời điểm câu trả lời này được viết. Tôi khuyên bạn nên sử dụngjQuery.when() thay vì các phương pháp này, nhưng tôi để lại câu trả lời cho các mục đích lịch sử.

-

Bạn có thể có được bằng một semaphore đếm đơn giản, mặc dù cách bạn triển khai nó sẽ phụ thuộc vào mã của bạn. Một ví dụ đơn giản sẽ giống như ...

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;

Nếu bạn muốn điều này hoạt động như {async: false} nhưng bạn không muốn khóa trình duyệt, bạn có thể thực hiện điều tương tự với hàng đợi 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
Điều này có vẻ như nó sẽ làm phức tạp quá mức một vấn đề tầm thường.
Chris

2
Nó thực sự không quá phức tạp. Đếm các semaphores là một cơ chế phổ biến trong CS. Nếu bạn thích mặc dù, ví dụ sử dụng hàng đợi jQuery cũng sẽ hoạt động mà không cần phải tự thực hiện semaphore.
BBonifield

1
Tôi không thấy vấn đề với bộ đếm semaphore, tuy nhiên, tôi thấy có vấn đề với ý tưởng có BỐN chức năng để xử lý cuộc gọi lại kết quả. Bạn nên xác định một chức năng trước, sau đó tham chiếu chức năng đó trong từng chức năng .get(). Bằng cách đó, ít nhất bạn không sao chép mã đó. Không chỉ vậy mà khai báo function(){}mỗi lần phân bổ bộ nhớ mỗi lần! Thực tế khá tệ nếu bạn có thể gọi một hàm được xác định tĩnh.
Alexis Wilke

1
@AlexisWilke Đây là một câu trả lời 4,5 năm tuổi và nó có nghĩa là một ví dụ về cách hoạt động của semaphores và hàng đợi. Bạn đang suy nghĩ quá nhiều về vấn đề này và tôi không nghĩ VỐN VỐN ĐỂ KIẾM MỘT ĐIỂM là cần thiết.
BBonifield

2
Chà ... tôi không phải là người cho bạn -1 ... và tôi hiểu rằng câu trả lời có xu hướng già đi. Tuy nhiên, mọi người tiếp tục tìm thấy chúng và theo như tôi biết thì không được phép cung cấp thông tin cho những người có khả năng sử dụng chúng cho đến ngày nay.
Alexis Wilke

8

javascript dựa trên sự kiện, vì vậy bạn không bao giờ nên chờ đợi , thay vào đó hãy đặt hook / callbacks

Bạn có thể chỉ cần sử dụng các phương pháp thành công / hoàn chỉnh của jquery.ajax

Hoặc bạn có thể sử dụng .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...
  }
});

mặc dù youy nên đăng một mã giả về cách (các) yêu cầu ajax của bạn được gọi là chính xác hơn ...


8

Một cách giải quyết nhỏ là như thế này:

// 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();
});

Hy vọng có thể hữu ích ...


Mặc dù các câu trả lời khác tốt hơn về mặt kỹ thuật vì nó dễ hiểu hơn, tôi thực sự thích câu trả lời này. Đẹp!
Jay

4

jQuery cho phép bạn chỉ định nếu bạn muốn yêu cầu ajax không đồng bộ hay không. Bạn có thể chỉ cần làm cho các yêu cầu ajax được đồng bộ hóa và sau đó phần còn lại của mã sẽ không thực thi cho đến khi chúng trở lại.

Ví dụ:

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

42
Một điều cần lưu ý là việc sử dụng {async: false} có thể tạm thời khóa trình duyệt. api.jquery.com/jQuery.ajax
BBonifield

30
Điều này chạy ngược lại với thực hành jQuery / Javascript tiêu chuẩn. AJAX luôn được coi là không đồng bộ. Bạn nên sử dụng jQuery.when () để thay thế.
SystemParadox

43
Đó là ý tưởng tồi tệ khủng khiếp! Đừng bao giờ làm thế! Chặn = không phản hồi hành động của người dùng, thậm chí là cuộn hoặc bất cứ điều gì! (Ngoài ra, async: false sẽ không được dùng nữa trong jQuery 1.8.)
skalee

5
Đặc biệt nếu yêu cầu không thành công hoặc mất nhiều thời gian vì một lý do không thể đoán trước (mà theo Luật của Murphy, chắc chắn sẽ xảy ra!), Đây thường là một ý tưởng tồi cho mã sản xuất do khóa trình duyệt như đã nêu ở trên.
Alex

27
Đây là một ý tưởng tồi tệ khủng khiếp. KHÔNG SỬ DỤNG TRẢ LỜI NÀY.
Tauren

2

Nếu bạn cần một cái gì đó đơn giản; một lần và thực hiện gọi lại

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

4
nó có thể tạo ra một vòng lặp vô tận!
Diego Favero 28/2/2015

2
Đây là một vòng lặp vô tận? Khi nào? Khi AJAX không bao giờ trở lại?
Jonathan

2

Ngoài ra, bạn có thể sử dụng async.js .

Tôi nghĩ rằng nó tốt hơn $ .when bởi vì bạn có thể hợp nhất tất cả các loại cuộc gọi không đồng bộ không hỗ trợ lời hứa ngoài hộp như thời gian chờ, cuộc gọi SqlLite, v.v. và không chỉ yêu cầu ajax.


2

Trên cơ sở câu trả lời @BBonifield, tôi đã viết một hàm tiện ích để logic semaphore không được lan truyền trong tất cả các lệnh gọi ajax.

untilAjax là hàm tiện ích gọi hàm gọi lại khi tất cả các ajaxCalls được hoàn thành.

ajaxObjslà một mảng các đối tượng thiết lập ajax [http://api.jquery.com/jQuery.ajax/].

fn là chức năng gọi lại

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;
  };

Ví dụ: doSomethinghàm sử dụng 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

Tôi thực sự khuyên bạn nên sử dụng $ .when () nếu bạn bắt đầu từ đầu.

Mặc dù câu hỏi này có hơn triệu câu trả lời, tôi vẫn không tìm thấy điều gì hữu ích cho trường hợp của mình. Giả sử bạn phải đối phó với một cơ sở mã hiện có, đã thực hiện một số cuộc gọi ajax và không muốn giới thiệu sự phức tạp của các lời hứa và / hoặc làm lại toàn bộ.

Chúng ta có thể dễ dàng tận dụng jQuery .data, .on.triggerchức năng mà đã là một phần của jQuery kể từ mãi mãi.

Codepen

Những thứ tốt về giải pháp của tôi là:

  • rõ ràng những gì gọi lại chính xác phụ thuộc vào

  • chức năng triggerNowOrOnLoadedkhông quan tâm nếu dữ liệu đã được tải hoặc chúng tôi vẫn đang chờ nó

  • Thật dễ dàng để cắm nó vào một mã hiện có

$(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

Tôi đang sử dụng kiểm tra kích thước khi tất cả tải ajax hoàn tất

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>


ngón tay cái lên đến ví dụ của bạn.
MarwaAhmad

2

Để mở rộng câu trả lời của Alex, tôi có một ví dụ với các đối số và lời hứa khác nhau. Tôi muốn tải hình ảnh qua ajax và hiển thị chúng trên trang sau khi tất cả chúng được tải.

Để làm điều đó, tôi đã sử dụng như sau:

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);
    }
});

Đã cập nhật để hoạt động cho một hoặc nhiều url: https://jsfiddle.net/euypj5w9/


2

Như các câu trả lời khác đã đề cập, bạn có thể sử dụng ajaxStop()để đợi cho đến khi tất cả yêu cầu ajax được hoàn thành.

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

Nếu bạn muốn thực hiện nó cho một ajax()yêu cầu cụ thể, cách tốt nhất bạn có thể làm là sử dụng complete()phương thức bên trong yêu cầu ajax nhất định:

$.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.
    }
});


Nhưng, nếu bạn chỉ cần đợi một vài và yêu cầu ajax nhất định sẽ được thực hiện? Sử dụng các javascript tuyệt vời hứa hẹn sẽ đợi cho đến khi các ajax bạn muốn chờ đợi được thực hiện. Tôi đã làm một ví dụ ngắn gọn, dễ đọc và dễ đọc để cho bạn thấy các lời hứa hoạt động như thế nào với ajax.
Hãy xem ví dụ tiếp theo . Tôi đã sử dụng setTimeoutđể làm rõ ví dụ.

// 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

Tôi tìm thấy cách đơn giản, nó sử dụng 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

Giải pháp của tôi là như sau

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);
          });

Làm việc khá độc đáo. Tôi đã thử rất nhiều cách khác nhau để làm điều này, nhưng tôi thấy đây là cách đơn giản nhất và có thể tái sử dụng nhiều nhất. Hy vọng nó giúp


0

Nhìn vào giải pháp của tôi:

1. Đưa chức năng này (và biến) vào tệp javascript của bạn:

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.Làm một mảng với các yêu cầu của bạn, như thế này:

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. Tạo chức năng gọi lại:

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

4.Call chức năng runFunctionQueue với các tham số:

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


-4

Hãy thử cách này. tạo một vòng lặp bên trong chức năng tập lệnh java để đợi cho đến khi cuộc gọi ajax kết thúc.

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
Của bạn setTimeout()KHÔNG take a sleep. Trong trường hợp này, bạn chỉ cần chặn tất cả các tab cho đến khi donetrở thành sự thật.
Alexis Wilke

1
Tôi nghĩ đó là chủ đề này yêu cầu: "Đợi cho đến khi tất cả các yêu cầu jQuery jQuery được thực hiện".
ChinaHelloWorld

1
Bạn đã thử mã này chưa? kỳ vọng của tôi là điều đó donesẽ không bao giờ đúng trong khi vòng lặp while vẫn đang chạy. Nếu vòng lặp while đang chạy, vòng lặp sự kiện không thể tiếp tục và do đó sẽ không bao giờ chạy lại cuộc gọi thành công ajax.
Kevin B
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.