Tìm kiếm trang web

javascript - Chờ cho đến khi tất cả các yêu cầu Ajax của jQuery hoàn tất?


Làm thế nào để tôi làm cho một hàm chờ cho đến khi tất cả các yêu cầu Ajax của jQuery hoàn tất bên trong một hàm khác?

Tóm lại, tôi cần chờ tất cả các yêu cầu Ajax hoàn tất trước khi thực hiện câu lệnh tiếp theo. Nhưng làm thế nào?

Câu trả lời #1

jQuery hiện nay định nghĩa một hàm when cho mục đích này.

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

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

$.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 ý kiến của tôi, điều đó tạo ra một cú pháp rõ ràng và sạch sẽ, và tránh việc sử dụng bất kỳ biến toàn cục nào như ajaxStart và ajaxStop, điều mà có thể gây ra cá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ần chờ bao nhiêu đối số ajax (tức là bạn muốn sử dụng một số lượng đối số thay đổi), vẫn có thể thực hiện được nhưng sẽ hơi phức tạp hơn một chút. Xem Truyền một mảng các Deferreds vào $.when() (và có thể jQuery .when khắc phục 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 script ajax v.v., bạn có thể lưu đối tượng được trả về bởi .when() - đó là một đối tượng jQuery Promise bao gồm tất cả các truy vấn ajax gốc. Bạn có thể gọi .then() hoặc .fail() trên nó để thêm các bộ xử lý chi tiết cho thành công/thất bại.

Câu trả lời #2

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

$(document).ajaxStop(function () {
  // 0 === $.active
  $(this).unbind('ajaxStop'); // to stop this event repeating further
});

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

Ở đây $.ajaxStop cũng có thể được liên kết với bất kỳ nút HTML nào mà bạn nghĩ rằng nó có thể bị thay đổi bởi yêu cầu.


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

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

Thú vị thay, điều này hoạt động với Promises cũng như các yêu cầu $.ajax.

Đây là bản 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) { }

Câu trả lời #3

Tôi đã tìm thấy một câu trả lời hay nhờ chính mình gnarf, đó 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 một yêu cầu ajax vào hàng đợi như sau:

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

Câu trả lời số 4

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

-

Bạn có thể có thể sử dụ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 có thể là something like...

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 không muốn khóa trình duyệt, bạn có thể đạt được cùng một điều với một 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();
    });
});

Câu trả lời số 5

Sử dụng sự kiện ajaxStop.

Ví dụ, giả sử bạn có một thông báo đang tải ... trong khi lấy 100 yêu cầu ajax và bạn muốn ẩn thông báo đó sau khi tải xong.

Từ tài liệu jQuery:

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

Hãy lưu ý rằng nó sẽ chờ tất cả các yêu cầu ajax trên trang đó hoàn tất.

Câu trả lời #6

Một cách xử lý tạm thời sẽ 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...

Câu trả lời số 7

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

Ví dụ:

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

Bài viết liên quan