Arrêtez d'essayer de faire fonctionner async/await
Les promesses sont tellement Fetch en ce moment
Depuis la nuit des temps, les développeurs se sont battus dans de nombreuses querelles absurdes. De la classique “Tabs vs. Spaces” au débat éternel “Mac vs. PC”, nous sommes doués pour trouver des arguments distrayants.
Réponses : Linux et espaces.
La querelle… ?
Promesses vs. Async/Await !
Attendez, est-ce une querelle ? C’est forcément le cas ? On ne parle plus des fonctions de rappel, semble-t-il ?
Non, ce n’est pas une querelle. Au final, il s’agit d’un outil supplémentaire dans votre trousseau d’outils. Cependant, puisque async/await ne remplace pas toute la fonctionnalité des Promises (notamment Promise.all, .race), il est trompeur de le présenter comme un remplacement.
Beaucoup de figures influentes promeuvent cette idée erronée selon laquelle async/await est le remplacement idéal des Promises attendu.
Indice : Non, non, et pas même un peu.
Une récente fonctionnalité de VS Code renforce cette idée fausse. Comme l’a tweeté @umaar :
Visual Studio Code peut désormais convertir vos longues chaînes de Promise.then() en async/await ! 🎊 Fonctionne très bien dans les fichiers JavaScript et TypeScript. .catch() est également correctement converti en try/catch ✅ pic.x.com/xb39Lsp84V
— Umar Hansa (@umaar) September 28, 2018
Si vous détestez les Promises et que vous souhaitez cette fonctionnalité de refactorisation, je ne vous en veux pas.
Je comprends. Je sais ce que c’est.
J’y suis passé. 🤗
Je détestais les Promises. Aujourd’hui, j’ai complètement changé d’avis. Les Promises sont incroyables. Elles vous permettent d’exploiter la composition des fonctions.
Il y a 2 domaines sur lesquels je recommande de se concentrer en premier pour améliorer sa maîtrise des Promises.
#1 : Fonctions nommées !
Éliminez les méthodes anonymes. L’utilisation de fonctions nommées fait en sorte que le code exprime vos exigences comme de la poésie.
Examinons un exemple courant :
Effectuer une requête HTTP GET avec fetch :
Anti-Pattern
// ❌ Utilisation de fonctions anonymes en ligne 💩fetch(url) .then(response => response.status < 400 ? response : Promise.reject(new Error('Request Failed: ' + response.ststus))) .then(response => response.text())Solution : Méthodes nommées
// ✅ La clarté émerge : fonctions nomméesfetch(url) .then(checkResponse) .then(getText)
// Fonctions réutilisables génériquesfunction checkResponse(response) { return response.status < 400 ? response : Promise.reject(new Error('Request Failed: ' + response.ststus))}function getText(response) { return response.text()}Les avantages de cette approche sont de plus en plus évidents lorsque votre code devient plus DRY.
Ressources supplémentaires : Découvrez mes vidéos de 1 minute sur le journalisation de base et le débogage avancé en utilisant cette technique.
#2: Objectif Unique (Fonctions)
Il semble précisément trompeur : Objectif Unique.
Pourtant, c’est si subjectif, arbitraire, et oui, parfois même sans sens.
// 1 point : le return & l'opérateur ternaire forment une ligne uniquefunction checkResponse(response) { return response.status < 400 ? response : Promise.reject(new Error('Request Failed: ' + response.ststus))}// 1 point : le return & l'expression forment une ligne uniquefunction getText(response) { return response.text()}Étant donné le code d’une fonction, ajoutez 1 point pour chaque ligne contenant l’un des éléments suivants : if, return, opérateur ternaire, for, const, let, var, switch, while, [].map/filter/reduce/etc. Ajoutez 1 point pour chaque instruction (ignorez les lignes supplémentaires dues aux espaces). Une série d’expressions ou de méthodes enchaînées ne compte que pour 1 point.
Whaou, c’était un peu technique.
Intéressant, la plupart des développeurs affirment être assez bons dans l’application du principe Objectif Unique à leur code. Coïncidence non liée : ils affirment aussi être de très bons conducteurs !
Examinons un exemple présenté par (exceptionnellement talentueux) Jake Archibald dans son article sur async/await pour le site Google Developers (note : lien retiré en 2024).
// source: https://developers.google.com/web/fundamentals/primers/async-functionsfunction logInOrder(urls) { // fetch all the URLs const textPromises = urls.map(url => { return fetch(url).then(response => response.text()); });
// log them in order textPromises.reduce((chain, textPromise) => { return chain.then(() => textPromise) .then(text => console.log(text)); }, Promise.resolve());}Fonction à usage unique ?
Je dirais non. Qu’est-ce que logInOrder fait exactement ?
- Parcourir une liste d’
urls - Appliquer une requête HTTP GET inline :
- Requête HTTP
fetch - Retourner le corps de texte de la réponse
- Ajouter un
.then(text => console.log(text))après chaque promesse danstextPromise - Afficher les résultats de manière séquentielle
Il y a 5 fonctions anonymes définies au sein de cette unique fonction. Comme le souligne Jake, la méthode .reduce est trop complexe. Il ne fait pas de sens de rédiger manuellement des mécanismes détaillés un peu partout dans son code. Pour reformuler, nous n’écrivons pas des codes de création de DOM avec des appels infinis à document.createElement(), element.setAttribute(), etc. Au lieu de cela, nous choisissons l’outil le plus adapté parmi plusieurs options : fonctions utilitaires, bibliothèques ou frameworks.
Remarque : Si l’intention était de lancer des requêtes de manière séquentielle, plutôt que simplement d’afficher les résultats dans l’ordre, ce code ne le fait pas effectivement. Nous allons procéder à un refactor correspondant.
Solution : Fonctions à objectif unique
Commencez par extraire des méthodes…

Poursuivez en remplaçant le .reduce() et logPromise() par un Promise.all et un ..map()…

Résumé
Essayez d’appliquer ces techniques à votre propre code ! Puis envoyez-moi un tweet pour me dire comment ça s’est passé. Ou si vous avez des questions ou des commentaires, contactez-moi également !
Aidez à faire connaître le #PromiseTruth et partagez cet article. ❤️
