2017-06-15 5 views
2

J'ai certaines fonctions qui renvoient des objets jQuery différés et j'ai de la difficulté à les enchaîner et à traiter les résultats.Fonctions de chaînage qui renvoient des objets différés

Prenons l'exemple suivant:

const start = Date.now(); 
 

 
// Print a message with a timestamp. 
 
function log (v) { 
 
    console.log(`${Date.now() - start} ${v}`); 
 
} 
 

 
// Return a deferred function that resolves 1 second later with 'value'. 
 
function test (value) { 
 
    log(`test(${value})`); 
 
    return $.Deferred(function (def) { 
 
     window.setTimeout(function() { 
 
      log(`resolve(${value})`); 
 
      def.resolve(value); 
 
     }, 1000); 
 
    }); 
 
} 
 

 
// Example: 
 
test(42) 
 
    .then(function (v) { log(v); }) 
 
    .then(test(99)) 
 
    .then(function (v) { log(v); }) 
 
    .then(function() { log('done'); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Ceci est supposé courir test(42), puis faire quelque chose avec ses résultats, puis exécutez test(99) puis faire quelque chose avec ces résultats, tout en commande. Cependant, il émet en fait (premier nombre est ms depuis le programme a commencé):

0 test(42) 
0 test(99) 
1003 resolve(42) 
1003 42 
1003 undefined <-- supposed to be 99 
1005 done 
1005 resolve(99) 

Alors les deux test s s'appelle en même temps dès le début, et tout le reste est éteint. Ce que je veux à la sortie est quelque chose comme:

0 test(42) 
1000 resolve(42) 
1000 42 
1000 test(99) 
2000 resolve(99) 
2000 99 
2000 done 

Comment puis-je faire ce travail? J'ai essayé de retourner $.Deferred(...).promise(), sans changement de comportement, et j'ai également essayé d'utiliser done au lieu de then mais le seul changement était-il imprimé 42 une seconde fois au lieu de undefined.

Répondre

1

Chaque différé ne résout qu'une seule fois. Pour chaque chaîne différée, vous devez les attacher correctement. De plus, le second appel à tester doit être dans une fonction afin qu'il ne s'exécute pas immédiatement.

const start = Date.now(); 
 

 
// Print a message with a timestamp. 
 
function log (v) { 
 
    console.log(`${Date.now() - start} ${v}`); 
 
} 
 

 
// Return a deferred function that resolves 1 second later with 'value'. 
 
function test (value) { 
 
    log(`test(${value})`); 
 
    return $.Deferred(function (def) { 
 
     window.setTimeout(function() { 
 
      log(`resolve(${value})`); 
 
      def.resolve(value); 
 
     }, 1000); 
 
    }); 
 
} 
 

 
// Example: 
 
test(42) 
 
    .then(function (v) { log(v); }) 
 
    .then(function() { 
 
     test(99) 
 
      .then(function (v) { log(v); }) 
 
      .then(function() { log('done'); }); 
 
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

+0

Ah, je vois, merci. Et les nicher comme ceci est la seule façon de le faire? Donc, si je construis une longue chaîne avec une boucle for ou quelque chose, je dois soit écrire une fonction d'aide pour les faire séquentiellement, soit finesse tout dans cette forme imbriquée? –

+1

Une fois une résolution différée, elle exécutera tout then() attaché à celle-ci, indépendamment du fait que l'un en contienne un autre différé ou non. Vous devez donc enchaîner votre logique avec cela en tête. – Taplar

+0

Btw, j'ai fait un peu d'expérience en jouant avec vos conseils, il semble * fonctionner * correctement si je * juste * faire le second appel à tester soit une fonction (qui retourne cet objet différé), même sans l'imbrication, [comme ceci] (https://pastebin.com/r5Eda5Zp). Peut-être que si le gestionnaire 'then' retourne quelque chose de lisible, cela change-t-il le fonctionnement du reste de la chaîne? –