Làm thế nào để bạn làm việc với một mảng của Trì hoãn jQuery?


132

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à lược đồ, cuối cùng khởi tạo ứng dụng với lược đồ và 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 thực theo lược đồ và được hiển thị. Khi người dùng CRUD dữ liệu, các lược đồ cung cấp xác thực thông qua đầu tiên.

Tôi đang gặp vấn đề với việc khởi tạo. Tôi sử dụng một lệnh gọi Ajax để tìm nạp đố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 đó làm việc. Tôi thấy tìm nạp trong giao diện điều khiển.

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

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

Điều này đã làm việc bằng Futures.js. Làm thế nào một mảng của Trì hoãn jQuery đượ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);
        });
    });

Tôi có một vấn đề gần như giống hệt nhau, ngoại trừ tôi cần kích hoạt phương thức "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ề làm điều này? Tôi đã thử sử dụng .pipe sau "fetch_one", nhưng dường như nó không hoạt động.
CambridgeMike

Câu trả lời:


198

Bạn đang tìm

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

Điều này cũng sẽ hoạt động (đối với một số giá trị của công việc, nó sẽ không sửa lỗi ajax bị hỏng):

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

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

Đã chế nhạo tất cả $ .ajax của bạn bằng cách thay thế chúng $.whenvà mẫu hoạt động

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


Cảm ơn bạn. Cú pháp này khác với thực hiện (). Fail () như thế nào?
Elf Sternberg

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

1
Ồ, và việc 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 hứa (), do đó, nó bị bỏ qua có lợi cho một đối tượng Trì hoãn được tạo bên trong (jQuery 1.5, dòng 943).
Elf Sternberg

1
@ElfSternberg nó thực sự không liên quan, nhưng để dễ đọc tôi không cần phải xem qua lần thứ hai $.when.apply($, .... Điều này nullkhiến tôi phải "chờ đợi, cái gì?". Đó là một vấn đề về phong cách và thực hành mã hóa. Tôi đã phải đọc nguồn để xác nhận thissẽ không ném tham chiếu null vào jQuery.when!
Raynos

7
Việc sử dụng null khiến tôi nghĩ rằng 'ok, đây là một cách giải quyết' (đúng là như vậy), trong khi nếu $ được sử dụng, sự chú ý của tôi sẽ bị chuyển hướng sang suy nghĩ về wtf mà $ dành cho.
Danyal Aytekin

53

Cách giải quyết ở 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 cho resolve()phương thức bị trì hoãn vì jQuery gọi done()fail()gọi lại với các tham số riêng lẻ, không phải là một mảng. Điều đó có nghĩa là chúng ta phải sử dụng argumentsmảng giả để có được tất cả các đối tượng được giải quyết / bị từ chối được trả về bởi mảng trả chậm, điều này thật xấu xí:

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

Vì chúng tôi đã thông qua một loạt các hoãn lại, sẽ rất tốt để lấy lại một loạt các kết quả. Nó cũng sẽ là tốt đẹp để lấy lại một mảng thực tế thay vì một mảng giả để chúng ta có thể sử dụng các phương thức như Array.sort().

Dưới đây là một giải pháp lấy cảm hứng từ when.js 's when.all()phương pháp mà địa chỉ 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ể chỉ cần chuyển vào một loạt các lời hứa / trì hoãn và nhận lại một loạt các đối tượng được giải quyết / bị từ chối trong cuộc gọi lại 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");
});

@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 sau đó () sẽ luôn theo thứ tự như các lệnh ajax trong var "hứa" trong khi ()?
netpoetica

6
Điều này nên được tích hợp sẵn vào jQuery, nhưng - nhóm jQuery đã từ chối yêu cầu nhiều lần. Trong khi đó, mọi người cứ đặt câu hỏi ở đây và mở các vé tương tự chống lại jQuery và chúng tôi kết thúc với việc triển khai vùng người dùng ở khắp mọi nơi và / hoặc các cuộc gọi khó xử để apply()... đi tìm.
mindplay.dk

Cảm ơn giải pháp này! Có cách nào để có được các mục thành công không nếu một (hoặc nhiều) thất bại?
doktoreas

tất cả những gì bạn đã làm ở đây là argumentsthao tác ẩn vào phương thức riêng của nó. Tuyệt vời để sử dụng lại, nhưng không giải quyết được "sự xấu xí" của việc phải đối phó arguments(bạn có thể dễ dàng có được:var schemas=Array.prototype.slice.call(arguments);)
cowbert

2
@crispyduck, không nên deferred.fail(...)đọc deferred.reject(...)?
Bob S

19

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

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

Tìm hiểu thêm về toán tử lây lan ES6 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Siverse_operator tìm tại đây


1
Vâng Mặc dù những người trong chúng ta sử dụng Coffeescript hoặc một trong những hậu duệ / kẻ bắt chước của nó đã có quyền truy cập vào nhà điều hành đó trong một thời gian.
Elf Sternberg

0

mở rộng 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)
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.