2010-05-04 49 views
55

Vì vậy, tôi có một trang tải và thông qua jquery.get thực hiện một số yêu cầu để điền các menu thả xuống với các giá trị của chúng.Đang đợi nhiều cuộc gọi không đồng bộ để hoàn thành trước khi tiếp tục

$(function() { 
    LoadCategories($('#Category')); 
    LoadPositions($('#Position')); 
    LoadDepartments($('#Department')); 

    LoadContact(); 
}; 

Sau đó gọi hàm LoadContact(); Cuộc gọi nào khác và khi nó trả về, nó sẽ điền tất cả các trường vào biểu mẫu. Vấn đề là thường xuyên, các trình đơn thả xuống không phải là tất cả dân cư, và do đó, nó không thể đặt chúng vào giá trị chính xác.

Những gì tôi cần để có thể làm, bằng cách nào đó có LoadContact chỉ thực thi khi các phương thức khác hoàn tất và gọi lại thực hiện xong.

Nhưng, tôi không muốn phải đặt một loạt cờ vào cuối các cuộc gọi lại, sau đó kiểm tra và phải kiểm tra cuộc gọi setTimeout đệ quy, trước khi gọi LoadContact() ;

Có điều gì đó trong jQuery cho phép tôi nói, "Thực hiện điều này, khi tất cả những việc này được thực hiện".

More Info Tôi đang nghĩ đến một cái gì đó dọc theo những dòng

$().executeAfter(
    function() { // When these are done 
     LoadCategories($('#Category')); 
     LoadPositions($('#Position')); 
     LoadDepartments($('#Department')); 
    }, 
    LoadContact // Do this 
); 

... nó sẽ cần phải theo dõi các cuộc gọi ajax điều đó xảy ra trong quá trình thực hiện các phương pháp, và khi họ là tất cả hoàn thành, gọi LoadContact;

Nếu tôi biết cách đánh chặn ajax đang được thực hiện trong hàm đó, tôi có thể viết một phần mở rộng jQuery để thực hiện việc này.

My Giải pháp

;(function($) { 
    $.fn.executeAfter = function(methods, callback) { 

     var stack = []; 

     var trackAjaxSend = function(event, XMLHttpRequest, ajaxOptions) { 
      var url = ajaxOptions.url; 

      stack.push(url); 
     } 

     var trackAjaxComplete = function(event, XMLHttpRequest, ajaxOptions) { 
      var url = ajaxOptions.url; 

      var index = jQuery.inArray(url, stack); 

      if (index >= 0) { 
       stack.splice(index, 1); 
      } 

      if (stack.length == 0) { 
       callback(); 
       $this.unbind("ajaxComplete"); 
      } 
     } 

     var $this = $(this); 

     $this.ajaxSend(trackAjaxSend) 
     $this.ajaxComplete(trackAjaxComplete) 

     methods(); 
     $this.unbind("ajaxSend"); 
    }; 
})(jQuery); 

này liên kết với các sự kiện ajaxSend trong khi các phương pháp đang được kêu gọi và giữ một danh sách các url (cần một id duy nhất tốt hơn mặc dù) được gọi. Nó sau đó unbinds từ ajaxSend để chỉ các yêu cầu chúng tôi quan tâm được theo dõi. Nó cũng liên kết với ajaxComplete và xóa các mục khỏi ngăn xếp khi chúng trở về. Khi stack đạt đến số không, nó thực hiện gọi lại của chúng ta, và hủy liên kết sự kiện ajaxComplete.

+4

Câu hỏi ngẫu nhiên ... câu hỏi của tôi trùng lặp như thế nào khi tôi hỏi 4 tháng trước đó? – CaffGeek

Trả lời

43

Bạn có thể sử dụng .ajaxStop() như thế này:

$(function() { 
    $(document).ajaxStop(function() { 
    $(this).unbind("ajaxStop"); //prevent running again when other calls finish 
    LoadContact(); 
    }); 
    LoadCategories($('#Category')); 
    LoadPositions($('#Position')); 
    LoadDepartments($('#Department')); 
}); 

này sẽ chạy khi tất cả các yêu cầu hiện tại đã kết thúc sau đó unbind chính vì vậy nó không chạy nếu cuộc gọi ajax tương lai trong trang thực thi. Ngoài ra, hãy chắc chắn để đặt nó trước khi cuộc gọi ajax của bạn, do đó, nó bị ràng buộc sớm, nó quan trọng hơn với .ajaxStart(), nhưng thực hành tốt nhất để làm điều đó với cả hai.

+0

Tốt, và dường như hoạt động trong kịch bản mà tôi có, nhưng, hãy thêm một lời nhắc nhở, có một cuộc gọi async thứ tư mất một thời gian dài, mà tôi không muốn đợi vì LoadContact không yêu cầu nó hoàn thành. Có cách nào để nói rằng CHỈ ba điều này cần phải được hoàn thành? – CaffGeek

+0

@Chad - Không, nếu bạn muốn chọn và chọn ... sẽ phải đặt một truy cập vào chính mình, không có cách nào để một người xử lý toàn cầu biết bạn quan tâm đến ai. –

+0

Tôi đã thêm một giải pháp xuất hiện để làm những gì tôi yêu cầu. Câu trả lời của bạn chắc chắn đã chỉ cho tôi đúng hướng! – CaffGeek

0

Nhưng, tôi không muốn phải đặt một loạt cờ vào cuối các cuộc gọi lại, sau đó kiểm tra và phải kiểm tra cuộc gọi setTimeout đệ quy, trước khi gọi LoadContact ();
Không cần setTimeout. Bạn chỉ cần kiểm tra trong mỗi cuộc gọi lại rằng tất cả ba danh sách được điền (hoặc thiết lập tốt hơn một bộ đếm, tăng nó trong mỗi cuộc gọi lại và chờ cho đến khi nó bằng 3) và sau đó gọi LoadContact từ gọi lại. Có vẻ khá dễ dàng với tôi.

phương pháp tiếp cận ajaxStop có thể hoạt động, tôi không quen với nó.

+0

Đây là những gì tôi đang cố gắng tránh. Các callbacks sẽ không biết gì, cũng không quan tâm về những gì chạy sau chúng, hoặc dựa vào chúng, hoặc nếu các callbacks khác đang thực hiện, hoặc cần phải. Đó chỉ là giới thiệu logic rất phức tạp. – CaffGeek

+0

Tôi thấy một giải pháp dễ dàng: chuyển hàm trợ giúp làm tham số cho LoadCategories, v.v. ('executeMeAfterCallback') với logic của bạn. Khá giống ajaxStop, nhưng cung cấp cho bạn nhiều quyền kiểm soát hơn đối với những yêu cầu bạn muốn tham gia. –

+0

BTW, có lý do nào bạn có ba phương pháp khác nhau để tải danh sách chứ không phải một phương pháp (với các tham số cần thiết, như url)? Chỉ tò mò thôi. –

7

Nếu bạn đang sử dụng Jquery 1.5 hay muộn, tôi nghi ngờ các đối tượng thu nhập hoãn lại là đặt cược tốt nhất của bạn: http://api.jquery.com/category/deferred-object/

Phương pháp helper, khi nào, cũng khá đẹp: http://api.jquery.com/jQuery.when/

+0

Đồng ý, đó là những gì tôi sử dụng bây giờ – CaffGeek

+1

Phần nào của giải quyết được vấn đề này? Có rất nhiều lựa chọn, thật khó để biết cách giải quyết vấn đề này. –

16

Mở rộng trên Tom Lianza's answer, $.when() bây giờ là một cách tốt hơn để thực hiện điều này hơn là sử dụng .ajaxStop().

Thông báo trước duy nhất là bạn cần đảm bảo các phương pháp không đồng bộ mà bạn cần phải đợi khi trả lại Deferred object. May mắn là các cuộc gọi jQuery ajax đã làm điều này theo mặc định. Vì vậy, để thực hiện các kịch bản từ các câu hỏi, các phương pháp cần được chờ đợi trên sẽ giống như thế này:

function LoadCategories(argument){ 
    var deferred = $.ajax({ 
     // ajax setup 
    }).then(function(response){ 
     // optional callback to handle this response 
    }); 
    return deferred; 
} 

Sau đó, để gọi LoadContact() sau khi cả ba cuộc gọi ajax đã trở lại, và tùy chọn thực hiện callbacks cá nhân của mình :

// setting variables to emphasize that the functions must return deferred objects 
var deferred1 = LoadCategories($('#Category')); 
var deferred2 = LoadPositions($('#Position')); 
var deferred3 = LoadDepartments($('#Department')); 

$.when(deferred1, deferred2, deferred3).then(LoadContact); 
Các vấn đề liên quan