web-dev-qa-db-fra.com

Promise.all: Ordre des valeurs résolues

En regardant MDN , cela ressemble à la values passée au callback then() de Promise.all contient les valeurs dans l'ordre des promesses. Par exemple:

var somePromises = [1, 2, 3, 4, 5].map(Promise.resolve);
return Promise.all(somePromises).then(function(results) {
  console.log(results) //  is [1, 2, 3, 4, 5] the guaranteed result?
});

Quelqu'un peut-il citer une spécification indiquant dans quel ordre values devrait être?

PS: Utiliser un code comme celui-ci montrait que cela semblait être vrai, bien que ce ne soit évidemment pas une preuve, cela aurait pu être une coïncidence.

153
Thorben Croisé

En bref, l'ordre est préservé .

Suivant la spécification à laquelle vous avez lié, Promise.all(iterable) prend un iterable (c'est-à-dire un objet qui prend en charge Iterator interface) en tant que paramètre et, plus tard, lors des appels PerformPromiseAll( iterator, constructor, resultCapability) avec elle, où ce dernier boucle sur iterable en utilisant IteratorStep(iterator) .
Cela signifie que si, si l’itéré vous donnez la permission à Promise.all(), il le sera quand même.

La résolution est implémentée via Promise.all() Resolve où chaque promesse résolue possède un emplacement interne [[Index]], qui marque l'index de la promesse dans l'entrée d'origine.


Tout cela signifie que la sortie est strictement ordonnée comme entrée tant que l'entrée est strictement ordonnée (par exemple, un tableau).

Vous pouvez voir cela en action dans le violon ci-dessous (ES6):

// Used to display results
const write = msg => {
  document.body.appendChild(document.createElement('div')).innerHTML = msg;
};

// Different speed async operations
const slow = new Promise(resolve => {
  setTimeout(resolve, 200, 'slow');
});
const instant = 'instant';
const quick = new Promise(resolve => {
  setTimeout(resolve, 50, 'quick');
});

// The order is preserved regardless of what resolved first
Promise.all([slow, instant, quick]).then(responses => {
  responses.map(response => write(response));
});
216
Nit

Oui, les valeurs dans results sont dans le même ordre que dans promises.

On pourrait citer la spécification ES6 sur Promise.all , bien que cela soit un peu compliqué en raison de l'utilisation de l'api itérateur et du constructeur générique de promesse. Cependant, vous remarquerez que chaque rappel du résolveur a un attribut [[index]] qui est créé dans l'itération array-promise et utilisé pour définir les valeurs du tableau de résultats.

26
Bergi

Comme les réponses précédentes l'ont déjà indiqué, Promise.all agrège toutes les valeurs résolues avec un tableau correspondant à l'ordre d'entrée des promesses d'origine (voir agrégation des promesses ).

Cependant, je tiens à souligner que la commande n'est conservée que du côté client!

Pour le développeur, il semble que les promesses aient été accomplies dans l’ordre mais, en réalité, elles sont traitées à des vitesses différentes. Il est important de savoir quand vous travaillez avec un serveur distant, car celui-ci peut recevoir vos promesses dans un ordre différent.

Voici un exemple illustrant le problème à l'aide de délais d'expiration:

Promise.all

const myPromises = [
  new Promise((resolve) => setTimeout(() => {resolve('A (slow)'); console.log('A (slow)')}, 1000)),
  new Promise((resolve) => setTimeout(() => {resolve('B (slower)'); console.log('B (slower)')}, 2000)),
  new Promise((resolve) => setTimeout(() => {resolve('C (fast)'); console.log('C (fast)')}, 10))
];

Promise.all(myPromises).then(console.log)

Dans le code ci-dessus, trois promesses (A, B, C) sont données à Promise.all. Les trois promesses s'exécutent à des vitesses différentes (C étant le plus rapide et B étant le plus lent). C'est pourquoi les déclarations console.log des promesses apparaissent dans cet ordre:

C (fast) 
A (slow)
B (slower)

Si les promesses sont AJAX, un serveur distant recevra ces valeurs dans cet ordre. Mais du côté client, Promise.all garantit que les résultats sont classés en fonction des positions initiales du tableau myPromises. C'est pourquoi le résultat final est:

['A (slow)', 'B (slower)', 'C (fast)']

Si vous souhaitez également garantir l'exécution réelle de vos promesses, vous aurez besoin d'un concept tel qu'une file d'attente de promesses. Voici un exemple utilisant p-queue (attention, vous devez envelopper toutes les promesses dans des fonctions):

File d'attente de promesse séquentielle

const PQueue = require('p-queue');
const queue = new PQueue({concurrency: 1});

// Thunked Promises:
const myPromises = [
  () => new Promise((resolve) => setTimeout(() => {
    resolve('A (slow)');
    console.log('A (slow)');
  }, 1000)),
  () => new Promise((resolve) => setTimeout(() => {
    resolve('B (slower)');
    console.log('B (slower)');
  }, 2000)),
  () => new Promise((resolve) => setTimeout(() => {
    resolve('C (fast)');
    console.log('C (fast)');
  }, 10))
];

queue.addAll(myPromises).then(console.log);

Résultat

A (slow)
B (slower)
C (fast)

['A (slow)', 'B (slower)', 'C (fast)']
25
Benny Neugebauer