Voici un exemple artificiel de ce qui se passe: http://jsfiddle.net/adamjford/YNGcm/20/
HTML:
<a href="#">Click me!</a>
<div></div>
JavaScript:
function getSomeDeferredStuff() {
var deferreds = [];
var i = 1;
for (i = 1; i <= 10; i++) {
var count = i;
deferreds.push(
$.post('/echo/html/', {
html: "<p>Task #" + count + " complete.",
delay: count
}).success(function(data) {
$("div").append(data);
}));
}
return deferreds;
}
$(function() {
$("a").click(function() {
var deferreds = getSomeDeferredStuff();
$.when(deferreds).done(function() {
$("div").append("<p>All done!</p>");
});
});
});
Je veux "Tout est fait!" à apparaître une fois toutes les tâches différées terminées, mais $.when()
ne semble pas savoir comment gérer un tableau d'objets différés. "Terminé!" se produit d'abord parce que le tableau n'est pas un objet différé, donc jQuery va de l'avant et suppose que c'est juste fait.
Je sais que l'on pourrait passer les objets dans la fonction comme $.when(deferred1, deferred2, ..., deferredX)
mais on ne sait pas combien d'objets différés il y aura lors de l'exécution dans le problème réel que j'essaie de résoudre.
$.when.apply
du tout pour obtenir le même résultat.Réponses:
Pour passer un tableau de valeurs à n'importe quelle fonction qui s'attend normalement à ce qu'il s'agisse de paramètres distincts, utilisez
Function.prototype.apply
, dans ce cas, vous avez besoin de:Voir http://jsfiddle.net/YNGcm/21/
Dans ES6, vous pouvez utiliser l'
...
opérateur d'étalement à la place:Dans les deux cas, puisqu'il est peu probable que vous sachiez à l'avance combien de paramètres formels le
.then
gestionnaire aura besoin, ce gestionnaire devra traiter learguments
tableau afin de récupérer le résultat de chaque promesse.la source
$.when
-f.apply(ctx, my_array)
va appelerf
avecthis == ctx
et les arguments sont mis au contenu demy_array
.$
vsnull
comme premier paramètre mérite d'être lu. Dans ce cas particulier, cela n'a pas d'importance.$
faut moins taper quenull
et vous êtes en sécurité lorsque l'$.when
implémentation change (pas que ce soit probable dans ce cas mais pourquoi ne pas resterthis
inchangé par défaut).Les solutions de contournement ci-dessus (merci!) Ne résolvent pas correctement le problème de récupération des objets fournis à la
resolve()
méthode du différé car jQuery appelle lesdone()
etfail()
rappels avec des paramètres individuels, pas un tableau. Cela signifie que nous devons utiliser learguments
pseudo-tableau pour obtenir tous les objets résolus / rejetés renvoyés par le tableau de différés, ce qui est laid: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 intéressant 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 de la méthode when.js
when.all()
qui résout ces problèmes: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 ceci:
la source
var toArray = function (args) { return deferreds.length > 1 ? $.makeArray(args) : [args]; }
au lieu deArray.prototype.slice.call
.Vous pouvez appliquer la
when
méthode à votre tableau:Comment travaillez-vous avec un tableau de jQuery différés?
la source
Lorsque vous appelez plusieurs appels AJAX parallèles, vous avez deux options pour gérer les réponses respectives.
Promises'
tableau et$.when
qui acceptepromise
s et son rappel.done
est appelé lorsque tous lespromise
s sont renvoyés avec succès avec les réponses respectives.Exemple
la source
$.when
.for ... in
sur un tableau?!)(not recommended)
2.Non d'accord -for ... in
est ok parce que le tableau contient uniquement les propriétés qui ont besoin (pas de propriétés supplémentaires). Thanx de toute façonArray.prototype
. Dans tous les cas, pour un code non critique pour les performances, il serait préférable d'utiliser à la.map
place d'une bouclefor
/push
, par exemplevar promises = capitalCities.map(ajaxRequest); $.when.apply($, promises).then(fillCountryCapitals)
- travail effectué.Comme alternative simple, qui ne nécessite pas
$.when.apply
ou unarray
, vous pouvez utiliser le modèle suivant pour générer une seule promesse pour plusieurs promesses parallèles:par exemple
Remarques:
promise = promise.then(newpromise)
la source
then()
appels de chaînage de manière similaire. Le comportement avec$.when
est d'agir comme il est parallèle (non enchaîné). Veuillez l'essayer avant de jeter une alternative utile car cela fonctionne :)Je veux en proposer un autre en utilisant $ .each:
Nous pouvons déclarer la fonction ajax comme:
Partie du code où nous créons un tableau de fonctions avec ajax pour envoyer:
Et les fonctions d'appel avec l'envoi ajax:
la source
Si vous transpilez et avez accès à ES6, vous pouvez utiliser la syntaxe de propagation qui applique spécifiquement chaque élément itérable d'un objet comme argument discret, exactement comme
$.when()
il en a besoin.Lien MDN - Syntaxe de propagation
la source
Si vous utilisez angularJS ou une variante de la bibliothèque Q promise, vous disposez d'une
.all()
méthode qui résout ce problème exact.voir l'API complète:
https://github.com/kriskowal/q/wiki/API-Reference#promiseall
https://docs.angularjs.org/api/ng/service/$q
la source
.map
ici, mais eh bien).J'ai eu un cas très similaire où je publiais dans une boucle each puis définissais le balisage html dans certains champs à partir des numéros reçus de l'ajax. J'ai ensuite dû faire une somme des valeurs (maintenant mises à jour) de ces champs et les placer dans un champ total.
Ainsi, le problème était que j'essayais de faire une somme sur tous les numéros mais aucune donnée n'était encore revenue des appels asynchrones ajax. J'avais besoin de compléter cette fonctionnalité dans quelques fonctions pour pouvoir réutiliser le code. Ma fonction externe attend les données avant d'aller ensuite faire des choses avec le DOM entièrement mis à jour.
la source