
Lors de la 71e réunion d'Ecma TC39, le projet et la mise en œuvre de référence de Promise.allSettled
, le troisième des quatre principaux combinateurs de promesses, seront examinés.
Auteurs : Jason Williams (BBC), Robert Pumley (Bloomberg), Matthias Binens (Google)
Champion : Matthias Binens (Google)
Étape : 3
Pour les fans de podcasts, dupliqués sur YouTube .
Introduction et motivation
Il existe quatre principaux combinateurs dans le monde des promesses:
Promise.all
. ES2015. Se ferme à la première promesse rejetée / rejetée.Promise.race
. ES2015. Se ferme à la première promesse en quelque sorte résolue / réglée.Promise.any
. Étape 1. Se termine à la première promesse satisfaite / remplie.Promise.allSettled
. Étape 3 → Étape 4. Ne ferme pas.
Tous sont largement représentés dans les bibliothèques utilisateur ordinaires, chacun d'eux est utile en soi et convient dans diverses situations.
L'application principale de ce combinateur se produit lorsque vous souhaitez effectuer une action immédiatement après avoir terminé de nombreuses demandes, qu'elles se soient terminées par un succès ou un échec. Les autres combinateurs de promesses sont fermés ( court-circuit ), rejetant les résultats des valeurs d'entrée qui ont perdu la course à un certain état du système. Promise.allSettled
est unique en ce qu'il attend toujours tous ceux dont il est responsable.
Promise.allSettled
renvoie une promesse, qui est exécutée avec le retour d'un tableau d'instantanés des états des promesses, mais seulement après que toutes les promesses d'origine ont été résolues.
D'où vient le nom allSettled?
Nous disons qu'une promesse est réglée ( réglée ) si elle n'est pas suspendue en attente , c'est-à-dire quand il est satisfait ou rejeté - une des deux choses. Pour comprendre la terminologie, jetez un œil à l'ancien document États et destins .
Et aussi, ce nom, allSettled
, est largement utilisé dans les bibliothèques existantes qui implémentent cette fonctionnalité. La liste sera ci-dessous.
Des exemples
Imaginez que vous devez parcourir un tableau de promesses et renvoyer une nouvelle valeur avec un état connu (qui se produit dans l'une des deux branches possibles de la logique).
function reflect(promise) { return promise.then( (v) => { return { status: 'fulfilled', value: v }; }, (error) => { return { status: 'rejected', reason: error }; } ); } const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ]; const results = await Promise.all(promises.map(reflect)); const successfulPromises = results.filter(p => p.status === 'fulfilled');
L'API proposée permet au développeur de traiter ces options, sans qu'il soit nécessaire de créer la fonction de reflect
indépendamment ou de stocker les résultats dans des variables temporaires. La nouvelle API ressemble à ceci:
const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ]; const results = await Promise.allSettled(promises); const successfulPromises = results.filter(p => p.status === 'fulfilled');
Si, pour une raison quelconque, nous avons besoin de promesses rejetées, nous devons probablement collecter les raisons de ce qui s'est passé. allSettled
rend cela tout aussi simple.
const promises = [ fetch('index.html'), fetch('https://does-not-exist/') ]; const results = await Promise.allSettled(promises); const errors = results .filter(p => p.status === 'rejected') .map(p => p.reason);
De vrais exemples
Le désir de savoir que toutes les demandes ont été traitées est assez courant, quel que soit le statut de chacune d’elles. Ceci est important lorsque vous souhaitez faire des améliorations progressives à l'avenir. Nous n'avons pas toujours besoin d'obtenir une réponse de l'API.
const urls = [ ]; const requests = urls.map(x => fetch(x));
En utilisant Promise.allSettled
vous pouvez écrire quelque chose qui est plus conforme à nos attentes.
Implémentations personnalisées
Dans d'autres langues
Des fonctionnalités similaires existent dans d'autres langues, sous des noms différents. Puisqu'il n'y a pas de mécanisme universel immédiatement compatible avec de nombreuses langues, ce document suit l'exemple des noms des bibliothèques listées ci-dessus. Voici à quoi cela ressemble dans d'autres langues:
- Rust -
futures::join
; - C # -
Task.WhenAll
. Vous pouvez utiliser try / catch ou TaskContinuationOptions.OnlyOnFaulted
; - Python -
asyncio.wait
avec l'option ALL_COMPLETED
- Java -
CompletableFuture.allOf
Matériaux pour étude ultérieure
Procès-verbal des réunions du TC39
Spécification
Implémentations