Comment travaillez-vous avec un tableau de jQuery Deferreds?

J'ai une application qui nécessite que les données soient chargées dans un certain ordre: L'URL racine, puis les schémas, puis enfin initialiser l'application avec les schémas et les URL pour les différents objets de données. Lorsque l'utilisateur navigue dans l'application, les objets de données sont chargés, validés par rapport au schéma et affichés. Lorsque l'utilisateur écrase les données, les schémas fournissent une validation de premier passage.

J'ai un problème avec l'initialisation. J'utilise un appel Ajax pour récupérer l'objet racine, $.lorsque(), et puis créez un tableau de promesses, un pour chaque objet de schéma. Qui fonctionne. Je vois le fetch dans la console.

Je vois alors l'extraction pour tous les schémas, donc chacun $.ajax () appel fonctionne. fetchschemas() renvoie en effet un tableau de promesses.

Cependant, cette dernière clause when () ne se déclenche jamais et le mot "DONE" n'apparaît jamais sur la console. Le code source de jquery-1.5 semble impliquer que "null" est acceptable en tant qu'objet à passer à $.lorsque.apply (), comme quand () va construire un objet interne Deferred () pour gérer la liste si aucun objet n'est passé.

Cela a fonctionné en utilisant des contrats à terme.js. Comment un tableau de jQuery Deferreds devrait-il être géré, sinon comme ceci?

    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);
        });
    });
129
demandé sur Bergi 2011-02-02 22:24:47

4 réponses

Vous cherchez

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

Cela fonctionnera également (pour une certaine valeur de travail, il ne corrigera pas ajax cassé):

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

Vous voudrez passer $ au lieu de null de sorte que this à l'intérieur $.when fait référence à jQuery. Cela ne devrait pas avoir d'importance pour la source mais c'est mieux que de passer null.

Moqué tous vos $.ajax pour les remplacer par $.when et l'échantillon œuvres

C'est donc soit un problème dans votre requête ajax soit le tableau auquel vous passez fetch_schemas.

192
répondu Raynos 2013-02-22 19:58:48

La solution de contournement ci-dessus (merci!) ne résout pas correctement le problème de récupérer les objets fournis à la méthode resolve() différée car jQuery appelle les rappels done() et fail() avec des paramètres individuels, pas un tableau. Cela signifie que nous devons utiliser le pseudo-tableau arguments pour obtenir tous les objets résolus/rejetés renvoyés par le tableau de deferreds, ce qui est laid:

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

Puisque nous avons passé un tableau de différés, ce serait bien de récupérer un tableau de résultats. Il serait aussi, soyez gentil de récupérer un tableau réel au lieu d'un pseudo-tableau afin que nous puissions utiliser des méthodes comme Array.sort().

Voici une solution inspirée par quand.méthode de JS when.all() qui résout ces problèmes:

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

Maintenant, vous pouvez simplement passer un tableau de deferreds / promises et récupérer un tableau d'objets résolus / rejetés dans votre callback, comme ceci:

$.when.all(promises).then(function(schemas) {
     console.log("DONE", this, schemas); // 'schemas' is now an array
}, function(e) {
     console.log("My ajax failed");
});
51
répondu crispyduck 2013-04-25 06:59:25

Si vous utilisez la version ES6 de javascript, il existe un opérateur spread (...) qui convertit un tableau d'objets en arguments séparés par des virgules.

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

Plus d'informations sur ES6 spread operator https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator trouver ici

18
répondu pashaplus 2015-03-28 08:16:49

S'Étend quand avec ce code:

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)
    }
}
0
répondu CALL ME TZ 2015-06-16 07:10:14