Как вы работаете с массивом jQuery Deferreds?

У меня есть приложение, которое требует загрузки данных в определенном порядке: корневой URL, затем схемы, а затем, наконец, инициализировать приложение со схемами и URL-адресами для различных объектов данных. Когда пользователь перемещается по приложению, объекты данных загружаются, проверяются по схеме и отображаются. Когда пользователь CRUD обрабатывает данные, схемы обеспечивают проверку первого прохода.

У меня проблема с инициализацией. Я использую Ajax-вызов для извлечения корневого объекта $.when(), а затем создаю массив обещаний, по одному для каждого объекта схемы. Это работает. Я вижу выборку в консоли.

Затем я вижу выборку для всех схем, поэтому каждый вызов $.ajax() работает. fetchschemas() действительно возвращает массив обещаний.

Однако это заключительное предложение when () никогда не срабатывает, и слово "DONE" никогда не появляется на консоли. Исходный код jquery-1.5, по-видимому, подразумевает, что "null" является приемлемым в качестве объекта для передачи в $.when.apply(), так как when () создаст внутренний объект Deferred() для управления списком, если объект не прошло в.

Это работало с использованием Futures.js. Как управлять массивом jQuery Deferreds, если не так?

    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);
        });
    });

4 ответа

Решение

Ты ищешь

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

Это также будет работать (для некоторой ценности работы это не исправит сломанный ajax):

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

Вы хотите пройти $ вместо null чтобы this внутри $.when относится к jQuery, Это не должно иметь значения для источника, но лучше, чем передача null,

Смоделировал все ваши $.ajax, заменив их $.when и образец работает

Так что это либо проблема в вашем ajax-запросе, либо в массиве, который вы передаете fetch_schemas.

Обходной путь выше (спасибо!) Не решает проблему возврата объектов, предоставленных отложенному resolve() метод, потому что JQuery вызывает done() а также fail() обратные вызовы с отдельными параметрами, а не массив. Это означает, что мы должны использовать arguments псевдомассив для получения всех разрешенных / отклоненных объектов, возвращаемых массивом deferreds, что ужасно:

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

Поскольку мы передали массив отсрочек, было бы неплохо вернуть массив результатов. Также было бы неплохо получить реальный массив вместо псевдомассива, чтобы мы могли использовать такие методы, как Array.sort(),

Вот решение, вдохновленное когда .jswhen.all() метод, который решает эти проблемы:

// 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;
    }
}

Теперь вы можете просто передать массив отсроченных / обещаний и вернуть массив разрешенных / отклоненных объектов в вашем обратном вызове, например, так:

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

Если вы используете версию javascript для ES6. Существует оператор распространения (...), который преобразует массив объектов в аргументы, разделенные запятыми.

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

Подробнее об операторе распространения ES6 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator найти здесь

Расширяется, когда с этим кодом:

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)
    }
}
Другие вопросы по тегам