8

Kể từ khi sử dụng $.Deferred Tôi đã chạy vào kịch bản này một vài lần: Tôi có một danh sách các giá trị mà mỗi giá trị mang lại một Đối tượng bị trì hoãn theo một cách nào đó và tôi muốn thực hiện gọi lại sau khi tất cả Đối tượng trì hoãn được giải quyết.Xử lý các mảng của các đối tượng trì hoãn

Một ví dụ cụ thể hơn sẽ là một cái gì đó như thế này:

var urls = [ 'foo.com', 'bar.com', 'baz.com', 'qux.com' ], 
    defers = [], defer; 

for(var i = 0, j = urls.length; i < j; i++){ 
    defer = $.ajax({ 
     url: 'http://' + urls[ i ] 
    }); 

    defers.push(defer); 
} 

$.when.apply(window, defers).done(function(){ 
    // Do Something 
}); 

Có một giải pháp thanh lịch hơn so với mã trong ví dụ của tôi?

+2

Tại sao bạn nghĩ rằng, điều này không thanh lịch? – topek

+0

Sau khi viết mã như thế này cho lần thứ 3, tôi bắt đầu nghĩ rằng đó là một kịch bản khá phổ biến và có thể được xử lý bởi khung công tác Deferred Objects theo cách tốt hơn mà tôi chỉ đơn giản là nhìn. –

Trả lời

3

Có, bạn không bao giờ nên tham chiếu giá trị tra cứu trong vòng lặp. Luôn tạo một bản sao.

var urls = [ 'foo.com', 'bar.com', 'baz.com', 'qux.com' ], 
    defers = [], defer; 

var urlsLength = urls.length; 
for(var i = 0, j = urlsLength; i < j; i++){ 
    defer = $.ajax({ 
     url: 'http://' + urls[ i ] 
    }); 

    defers.push(defer); 
} 

$.when.apply(window, defers).done(function(){ 
    // Do Something 
}); 

Nhưng nghiêm túc, tôi chỉ là bạn. Mã đá đó. Gắn bó với nó.

+1

Bạn chính xác về giá trị tra cứu nhưng có nó trong khai báo (tức là 'var i = 0, j = urls.length') lưu trữ nó. Những gì bạn muốn tránh là có nó trong so sánh (tức là 'i

0

Đây là một chức năng helper tôi đã viết gọi LoadInitialData, nó có thể được gọi như thế này LoadInitialData(urlArray, dataReturnedArray, callback)

/// 
/// 1. The magical function LoadInitialData 
/// 

      /// 
      /// <summary> 
      /// This functions allows you to fire off a bunch of ajax GET requests and run a callback function when 
      /// all the requests come back that contains an array of all your ajax success data 
      /// </summary> 
      /// <params> 
      ///   urlArray - an array of urls to be looped and ajaxed 
      /// dataReturnedArray - this array will contain all data returned from your ajax calls. Its stuctured like this 
      ///   [{url: "http//site.com/1", "data": "your data"}, {url: "http//site.com/2", "data": "your data"}] 
      ///   dataReturnedArray[0] is data from call 1, dataReturnedArray[1] is data from call 2 etc. It might be a 
      ///   good idea to pass in a global array so you can use this data throughout your application. 
      ///  callback - a function that runs after all ajax calles are done, dataReturnedArray is available in the callback 
      /// </parms> 
      /// 
      function LoadInitialData(urlArray, dataReturnedArray, callback){ 
       // set up a deffered promise to fire when all our async calls come back 
       var urls = urlArray, defers = [], defer; 
        var urlsLength = urls.length; 
        for(var i = 0, j = urlsLength; i < j; i++){ 
         var u = urls[ i ]; 
          defer = $.ajax({ 
          type : "GET", 
          dataType : "jsonp", 
          url: u, 
          success: function(data){ 
           dataReturnedArray.push({ 
             url: u, 
             data: data 
           }); 
          } 
         }); 
         defers.push(defer); 
        } 
        $.when.apply(window, defers).then(function(){ 
          // Do Something now that we have all the data 
         console.log("done fetching all data"); 
         callback(dataReturnedArray); 
        }); 
      } 



/// 
/// 2. Your config…. urlArray, dataReturnedArray, callback 
/// 

     var app = app || {}; 
     app.data = []; // will hold the fetched data 
     var urlArr = ["http://site.com/2", "http://site.com/2"]; // the urls to get data from 


     // function to call once all the data is loaded 
     callback = function(data){ 

      // data cleansing 
      var tblData = [];       
      $.each(data, function(key, value){ 
        $.each(value.data, function(key, value){ 
          tblData.push(value); 
        }); 
      }); 

      $("#loader").hide(); 
     }; 


/// 
/// 3. Kick it all off! 
/// 

     // show a loader here 
     $("#loader").show(); 

     // fire off the code to fetch the initial data 
     LoadInitialData(urlArr, app.data, callback); 
3

Một cách thanh lịch hơn để viết ví dụ này là với chức năng bản đồ mảng (hoặc của jQuery $ .map):

var urls = [ 'foo.com', 'bar.com', 'baz.com', 'qux.com' ]; 

var defers = urls.map(function(url) { 
    return $.ajax({ 
     url: 'http://' + url 
    }); 
}); 

$.when.apply(window, defers).done(function(){ 
    // Do Something 
}); 

bạn thậm chí có thể cuộn "fetchURL" chức năng "whenDone" của riêng bạn và:

Array.prototype.whenDone = function(callback){ 
    return $.when.apply(window, this).done(callback); 
} 

function fetchURL(url){ 
    return $.ajax({ 
     url: 'http://' + url 
    }); 
} 

var urls = [ 'foo.com', 'bar.com', 'baz.com', 'qux.com' ];  

urls.map(fetchUrl).whenDone(function(){ 
    // Do Something 
}); 
+0

Tôi thích sử dụng 'Array.prototype.map'. Đó là sạch hơn. –