web-dev-qa-db-fra.com

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. À mesure que 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 redéfinit les données, les schémas fournissent une validation de premier passage.

J'ai un problème d'initialisation. J'utilise un appel Ajax pour récupérer l'objet racine, $ .when (), puis crée un tableau de promesses, un pour chaque objet de schéma. Ça marche. Je vois le chercher dans la console.

Je vois ensuite chercher pour tous les schémas, donc chaque appel à $ .ajax () 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 à transmettre à $ .when.apply (), car when () construira un objet interne Deferred () pour gérer la liste si aucun objet n'est présent. passé en.

Cela a fonctionné en utilisant Futures.js. Comment un tableau de jQuery Deferreds doit-il être géré, si ce n’est comme cela?

    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);
        });
    });
130
Elf Sternberg

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 valeur de travail, cela ne résoudra pas le problème ajax cassé):

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

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

Mocked tous vos $ .ajax en les remplaçant par $.when et l'exemple fonctionne

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

194
Raynos

La solution de contournement ci-dessus (merci!) Ne résout pas correctement le problème de récupération des objets fournis à la méthode resolve() du différé car jQuery appelle les rappels done() et fail() avec des paramètres individuels et non 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 reports, ce qui est moche:

$.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, il serait bien de récupérer un tableau de résultats. Il serait également agréable de récupérer un tableau réel au lieu d'un pseudo-tableau afin que nous puissions utiliser des méthodes telles que Array.sort().

Voici une solution inspirée par la méthode when.all() de when.js / 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 différés/promesses et récupérer un tableau d'objets résolus/rejetés dans votre rappel, comme suit:

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

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

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

En savoir plus sur l'opérateur de propagation ES6 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator find here

18
pashaplus

é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
CALL ME TZ