2011-02-02 55 views
128

Tôi có một ứng dụng yêu cầu dữ liệu được tải theo một thứ tự nhất định: URL gốc, sau đó là các lược đồ, sau đó cuối cùng khởi tạo ứng dụng với các lược đồ và các url cho các đối tượng dữ liệu khác nhau. Khi người dùng điều hướng ứng dụng, các đối tượng dữ liệu được tải, xác nhận hợp lệ với lược đồ và được hiển thị. Khi người dùng CRUDs dữ liệu, các lược đồ cung cấp xác thực thông qua đầu tiên.Làm thế nào để bạn làm việc với một mảng jQuery hoãn lại?

Tôi gặp sự cố khi khởi chạy. Tôi sử dụng một cuộc gọi Ajax để lấy đối tượng gốc, $ .when(), và sau đó tạo một mảng các lời hứa, một cho mỗi đối tượng lược đồ. Điều đó hoạt động. Tôi thấy tìm nạp trong bảng điều khiển.

Sau đó tôi thấy tìm nạp cho tất cả các lược đồ, do đó, mỗi lệnh $ .ajax() hoạt động. fetchschemas() thực sự trả về một loạt các lời hứa.

Tuy nhiên, điều khoản cuối cùng khi() không bao giờ kích hoạt và từ "XONG" không bao giờ xuất hiện trên bảng điều khiển. Mã nguồn để jquery-1.5 có vẻ ngụ ý rằng "null" được chấp nhận như một đối tượng để truyền tới $ .when.apply(), như khi() sẽ xây dựng một đối tượng Deferred() nội bộ để quản lý danh sách nếu không có đối tượng nào được chuyển giao.

Điều này đã làm việc khi sử dụng Futures.js. Làm thế nào nên một mảng jQuery Deferreds được quản lý, nếu không như thế này?

var fetch_schemas, fetch_root; 

    fetch_schemas = function(schema_urls) { 
     var fetch_one = function(url) { 
      return $.ajax({ 
       url: url, 
       data: {}, 
       contentType: "application/json; charset=utf-8", 
       dataType: "json" 
      }); 
     }; 

     return $.map(schema_urls, fetch_one); 
    }; 

    fetch_root = function() { 
     return $.ajax({ 
      url: BASE_URL, 
      data: {}, 
      contentType: "application/json; charset=utf-8", 
      dataType: "json" 
     }); 
    }; 

    $.when(fetch_root()).then(function(data) { 
     var promises = fetch_schemas(data.schema_urls); 
     $.when.apply(null, promises).then(function(schemas) { 
      console.log("DONE", this, schemas); 
     }); 
    }); 
+0

Tôi đã gần như một vấn đề giống hệt nhau, ngoại trừ tôi cần phải bắn một phương pháp "thành công" cho mỗi truy vấn ajax trong fetch_one, trước khi "DONE" được in. Làm thế nào bạn sẽ đi về việc này? Tôi đã thử sử dụng .pipe sau "fetch_one", nhưng điều đó dường như không hoạt động. – CambridgeMike

Trả lời

187

Bạn đang tìm kiếm

$.when.apply($, promises).then(function(schemas) { 
    console.log("DONE", this, schemas); 
}, function(e) { 
    console.log("My ajax failed"); 
}); 

này cũng sẽ làm việc (đối với một số giá trị của tác phẩm, nó sẽ không sửa chữa ajax vỡ):

$.when.apply($, promises).done(function() { ... }).fail(function() { ... });` 

Bạn sẽ muốn để vượt qua $ thay vì null sao cho this bên trong $.when đề cập đến jQuery. Nó không quan trọng đối với nguồn nhưng nó tốt hơn sau đó đi qua null.

chế giễu ra tất cả $ .ajax của bạn bằng cách thay thế chúng bằng $.when và mẫu works

Vì vậy, nó là một trong hai vấn đề trong yêu cầu ajax của bạn hoặc mảng đi qua của bạn để fetch_schemas.

+0

Cảm ơn bạn. Cú pháp này khác với cú pháp done(). Failed() như thế nào? –

+2

@elf Sternberg, '.then (a, b) === .done (a) .fail (b)' đó là một cách viết tắt lười biếng. Bạn có thể gọi '.done (a) .fail (b)' nếu bạn muốn – Raynos

+1

Ồ, và sử dụng $ .when.apply ($, ...) và $ .when.apply (null, ...) dường như không liên quan. Bản thân jQuery không có phương thức promise(), vì vậy nó bị bỏ qua để ủng hộ đối tượng Delferred được tạo nội bộ (jQuery 1.5, dòng 943). –

50

Cách khắc phục ở trên (cảm ơn!) Không giải quyết đúng vấn đề lấy lại các đối tượng được cung cấp theo phương thức resolve() bị trì hoãn vì jQuery gọi các cuộc gọi lại done()fail() với các tham số riêng lẻ chứ không phải mảng. Điều đó có nghĩa chúng ta phải sử dụng arguments pseudo-mảng để có được tất cả các giải quyết/từ chối đối tượng được trả về bởi các mảng của deferreds, mà là xấu xí:

$.when.apply($, promises).then(function() { 
    var schemas=arguments; // The array of resolved objects as a pseudo-array 
    ... 
}; 

Kể từ khi chúng tôi đi qua trong một mảng của deferreds, nó sẽ được tốt đẹp để lấy lại một loạt các kết quả. Nó cũng sẽ được tốt đẹp để lấy lại một mảng thực tế thay vì một mảng giả để chúng tôi có thể sử dụng các phương pháp như Array.sort().

Đây là giải pháp được lấy cảm hứng từ khi nào.js 's when.all() phương pháp nhằm giải quyết những vấn đề này:

// Put somewhere in your scripting environment 
if (jQuery.when.all===undefined) { 
    jQuery.when.all = function(deferreds) { 
     var deferred = new jQuery.Deferred(); 
     $.when.apply(jQuery, deferreds).then(
      function() { 
       deferred.resolve(Array.prototype.slice.call(arguments)); 
      }, 
      function() { 
       deferred.fail(Array.prototype.slice.call(arguments)); 
      }); 

     return deferred; 
    } 
} 

Bây giờ bạn có thể dễ dàng vượt qua trong một mảng của deferreds/lời hứa và nhận lại một loạt các giải quyết/từ chối đối tượng trong callback của bạn, như vậy:

$.when.all(promises).then(function(schemas) { 
    console.log("DONE", this, schemas); // 'schemas' is now an array 
}, function(e) { 
    console.log("My ajax failed"); 
}); 
+0

Wow, điều này hoạt động hoàn hảo; ý tưởng tuyệt vời. Cảm ơn! –

+0

@crispyduck - bạn có biết nếu bạn có thể chắc chắn 100% rằng thứ tự của các phần tử mảng trong "lược đồ" var trong đó() sẽ luôn theo thứ tự như các cuộc gọi ajax trong "hứa ​​hẹn" var trong khi nào()? – netpoetica

+1

điều này đã lưu ass của tôi, cảm ơn! –

17

Nếu bạn đang sử dụng phiên bản ES6 của javascript Có một toán tử spread (...) chuyển đổi mảng đối tượng thành các đối số được phân cách bằng dấu phẩy.

$.when(...promises).then(function() { 
var schemas=arguments; 
}; 

Thông tin thêm về điều hành lây lan ES6 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator tìm thấy ở đây

+0

Yup. Mặc dù những người trong chúng ta sử dụng Coffeescript hoặc một trong những con cháu của nó/người bắt chước đã có quyền truy cập vào nhà điều hành đó trong một thời gian. –

+0

bạn cũng không thể mở rộng lược đồ của mình? – matthewdaniel

0

kéo dài khi với mã này:

var rawWhen = $.when 
$.when = function(promise) { 
    if ($.isArray(promise)) { 
     var dfd = new jQuery.Deferred() 
     rawWhen.apply($, promise).done(function() { 
      dfd.resolve(Array.prototype.slice.call(arguments)) 
     }).fail(function() { 
      dfd.reject(Array.prototype.slice.call(arguments)) 
     }) 
     return dfd.promise() 
    } else { 
     return rawWhen.apply($, arguments) 
    } 
} 
Các vấn đề liên quan