Как вы работаете с массивом jQuery Deferreds? - PullRequest
130 голосов
/ 02 февраля 2011

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

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

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

Однако это предложение final () никогда не срабатывает, и слово «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 ]

196 голосов
/ 02 февраля 2011

Вы ищете

$.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.

53 голосов
/ 25 апреля 2013

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

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

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

. Вот решение, вдохновленное when.js when.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");
});
18 голосов
/ 28 марта 2015

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

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

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

0 голосов
/ 16 июня 2015

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

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