2014-07-11 18 views
9

Tôi có một chuỗi các url đơn giản và tôi muốn tải từng url một với jQuery. Tôi đã sử dụng $.get, nhưng tôi không thể làm cho nó hoạt động với $.Deferred, vì vậy tôi đã chuyển sang $.ajax - Tôi gần như đã làm việc, nhưng kết quả tôi nhận được là .. odd. Tôi đã hy vọng một ai đó có thể giúp tôi làm cho công việc này tốt hơn.

var results = [], files = [ 
    'url1', 'url2', 'url3' 
]; 

$.when(
    $.ajax(files[0]).done(function(data) { 
     results.push(data); console.log("step 1.0"); 
    }), 
    $.ajax(files[1]).done(function(data) { 
     results.push(data); console.log("step 1.1"); 
    }), 
    $.ajax(files[2]).done(function(data) { 
     results.push(data); console.log("step 1.2"); 
    }) 
).then(function(){ 
    console.log("step 2"); 
}); 

nên sản lượng này ..

  • bước 1.0
  • bước 1.1
  • bước 1.2
  • bước 2

Và sau đó các mảng results chứa kết quả của tất cả 3 yêu cầu ajax. Điều này có thể không?

+1

Sự cố bạn đang gặp phải với vấn đề này là gì? Các yêu cầu có thể hoàn thành theo thứ tự khác, vì vậy bạn có thể kết thúc bằng 'bước 1.2, bước 1.0, bước 1.1, bước 2', nhưng mảng sẽ luôn được điền trước khi 'then()' được thực hiện. –

+0

Tôi hoàn toàn cần chúng để hoàn thành đúng thứ tự. Điều quan trọng là mã hoạt động chính xác. – Ciel

+0

Tôi nhận được các kết quả khác nhau.Tôi nhận được 'bước 2' bắn trước bất kỳ bước 1s nào. – Ciel

Trả lời

8

Trước hết, bạn phải quyết định nếu bạn muốn ba ajax của bạn gọi để được xử lý song song (chạy tất cả cùng một lúc, với thời gian chạy ít hơn tổng thể) hoặc theo thứ tự mà một cuộc gọi ajax chạy, hoàn thành và sau đó bạn khởi chạy cuộc gọi ajax tiếp theo. Đây là một quyết định thiết kế quan trọng tác động đến cách bạn làm điều này.

Khi bạn sử dụng $.when(), bạn sẽ khởi chạy cả ba cuộc gọi ajax song song. Nếu bạn kiểm tra kết quả chỉ khi tất cả đã hoàn thành, bạn vẫn có thể xử lý kết quả theo một thứ tự cụ thể (vì bạn sẽ chỉ xử lý chúng khi tất cả kết quả có sẵn và chúng sẽ có sẵn theo thứ tự được yêu cầu). Nhưng, khi thực hiện nó theo cách này, tất cả các cuộc gọi ajax sẽ được gửi đi ngay lập tức. Điều này sẽ cung cấp cho bạn một thời gian end-to-end tốt hơn vì vậy nếu điều này là khả thi cho các loại yêu cầu, đây thường là một cách tốt hơn để làm điều đó.

Để làm điều đó, bạn có thể cơ cấu lại những gì bạn phải một cái gì đó như thế này:

chạy song song

var files = [ 
    'url1', 'url2', 'url3' 
]; 

$.when($.ajax(files[0]),$.ajax(files[1]),$.ajax(files[2])).done(function(a1, a2, a3) { 
    var results = []; 
    results.push(a1[0]); 
    results.push(a2[0]); 
    results.push(a3[0]); 
    console.log("got all results") 
}); 

Bởi vì bạn đang chờ đợi cho đến khi xử lý .done() cho $.when() đã được gọi là, tất cả các kết quả ajax đã sẵn sàng cùng một lúc và chúng được trình bày bởi $.when() theo thứ tự chúng được yêu cầu (bất kể cái nào thực sự đã hoàn thành trước), vì vậy bạn nhận được kết quả nhanh nhất có thể và chúng được trình bày theo thứ tự có thể dự đoán được. Lưu ý, tôi cũng đã chuyển định nghĩa của mảng results thành bộ xử lý thực hiện $.when() vì đó là nơi duy nhất bạn biết dữ liệu thực sự hợp lệ (vì lý do thời gian).


chạy song song - Lặp Arbitrary Chiều dài Mảng

Nếu bạn đã có một mảng lâu hơn, bạn có thể tìm thấy nó tốt hơn để lặp qua mảng của bạn với một cái gì đó giống như .map() để xử lý tất cả trong một vòng lặp thay hơn cách liệt kê chúng riêng lẻ:

var files = [ 
    'url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7' 
]; 

$.when.apply($, files.map(function(url) { 
    return $.ajax(url); 
})).done(function() { 
    var results = []; 
    // there will be one argument passed to this callback for each ajax call 
    // each argument is of this form [data, statusText, jqXHR] 
    for (var i = 0; i < arguments.length; i++) { 
     results.push(arguments[i][0]); 
    } 
    // all data is now in the results array in order 
}); 

chuỗi Ajax gọi

Nếu, mặt khác, bạn thực sự muốn sắp xếp các cuộc gọi ajax để cuộc gọi thứ hai không bắt đầu cho đến khi cuộc gọi đầu tiên kết thúc (có thể cần thiết nếu cuộc gọi ajax thứ hai cần kết quả từ cuộc gọi ajax đầu tiên để biết yêu cầu hoặc làm gì), thì bạn cần một mẫu thiết kế hoàn toàn khác và $.when() không phải là cách để đi chút nào (nó chỉ thực hiện các yêu cầu song song). Trong trường hợp đó, bạn có thể chỉ muốn kết quả chuỗi của bạn với x.then().then() và sau đó bạn có thể xuất báo cáo nhật ký theo thứ tự mà bạn yêu cầu như thế này.

$.ajax(files[0]).then(function(data0) { 
     console.log("step 1.0"); 
     return $.ajax(files[1]); 
    }).then(function(data1) { 
     console.log("step 1.1"); 
     return $.ajax(files[2]); 
    }).done(function(data2) { 
     console.log("step 1.2"); 
     // all the ajax calls are done here 
     console.log("step 2"); 
    }); 

điều khiển Output:

step 1.0 
step 1.1 
step 1.2 
step 2 

Cấu trúc này cũng có thể được đưa vào một vòng lặp để tự động chạy nó cho N cuộc gọi ajax tuần tự nếu mảng của bạn các tập tin dài. Trong khi bạn có thể thu thập kết quả khi bạn đi vào mảng results, thường là lý do mọi thứ được thực hiện tuần tự là kết quả trước đó được tiêu thụ bởi cuộc gọi ajax tiếp theo, do đó bạn thường chỉ cần kết quả cuối cùng. Nếu bạn muốn thu thập kết quả khi bạn đi, bạn có thể đẩy chúng vào mảng results ở mỗi bước.

Lưu ý, những lợi thế hứa hẹn cung cấp ở đây để bạn có thể thực hiện các thao tác chuỗi trong khi vẫn ở cùng mức độ lồng nhau và không được lồng ghép thêm nữa.


Chuỗi Ajax cuộc gọi - Lặp Arbitrary Chiều dài Mảng

Dưới đây là những gì các trình tự sẽ như thế nào trong một vòng lặp:

var files = [ 
    'url1', 'url2', 'url3', 'url4', 'url5', 'url6', 'url7' 
]; 

var results = []; 
files.reduce(function(prev, cur, index) { 
    return prev.then(function(data) { 
     return $.ajax(cur).then(function(data) { 
      console.log("step 1." + index); 
      results.push(data); 
     }); 
    }) 
}, $().promise()).done(function() { 
    // last ajax call done 
    // all results are in the results array 
    console.log("step 2.0"); 
}); 

điều khiển Output:

step 1.0 
step 1.1 
step 1.2 
step 1.3 
step 1.4 
step 1.5 
step 1.6 
step 2 

Phương thức Array.prototype.reduce() wo rks handily ở đây vì nó tích lũy một giá trị duy nhất khi bạn xử lý từng phần tử mảng riêng lẻ, đó là những gì bạn cần làm khi bạn thêm .then() cho mỗi phần tử mảng. Việc lặp lại .reduce() được bắt đầu bằng lời hứa trống/đã giải quyết với $().promise() (có nhiều cách khác để tạo lời hứa như vậy), điều này chỉ cung cấp cho chúng tôi thứ gì đó để bắt đầu thực hiện .then() trên đó đã được giải quyết.

+0

Điều này cực kỳ hữu ích. Tôi bắt đầu thấy sự khôn ngoan trong việc sử dụng một thư viện bên ngoài, ngay cả với chi phí có thể nó có thể phải chịu. Ngay bây giờ tôi chỉ cần làm điều này ở một nơi, nhưng nếu tôi cần phải làm điều đó hai hay nhiều lần, số lượng công việc thêm để làm cho nó hoạt động trở nên gây tổn hại nhiều hơn. – Ciel

+0

@Ciel - Tôi không hiểu nhận xét của bạn. Tại sao bạn cần một thư viện bên ngoài? Bạn có thể thực hiện bất kỳ tùy chọn nào trong số các tùy chọn này thành chức năng có thể tái sử dụng chỉ với một vài dòng mã. – jfriend00

+0

Xin lỗi. Tôi đã có một chút mất tập trung, và hôm nay chỉ có cơ hội để thực sự thử điều này. Cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn, tôi đã học được rất nhiều từ ví dụ này một mình. – Ciel

2

Bạn nên truy cập giá trị trả lại từ .then thay vì mỗi .done. Ngoài ra, .map là bạn của bạn.

var results = [], files = [ 
    'url1', 'url2', 'url3' 
]; 

$.when.apply($, $.map(files, function (file) { 
    return $.ajax(file); 
})).then(function (dataArr) { 
    /* 
    * dataArr is an array of arrays, 
    * each array contains the arguments 
    * returned to each success callback 
    */ 
    results = $.map(dataArr, function (data) { 
     return data[0]; // the first argument to the success callback is the data 
    }); 
    console.log(results); 
}); 

các đối số truyền cho .Sau đó sẽ nằm trong thứ tự mà chúng được thông qua để .Khi

+1

Tôi không nghĩ rằng bạn đang xử lý dữ liệu từ '$ .when()' một cách chính xác. Nó không cung cấp cho bạn một đối số duy nhất là một mảng các mảng. Nó cung cấp cho bạn một loạt các đối số trong đó mỗi đối số là một mảng của ba giá trị. Xem ví dụ về mã thứ hai đến cuối cùng tại đây http://api.jquery.com/jquery.when/ trên dòng 3. – jfriend00