DanLevy.net

Arrêtez d'essayer de faire fonctionner async/await

Les promesses sont tellement Fetch en ce moment

Hero image for Arrêtez d'essayer de faire fonctionner async/await

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 (pas anonymes)
  2. Fonctions à usage unique

#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ées
fetch(url)
.then(checkResponse)
.then(getText)
// Fonctions réutilisables génériques
function 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 unique
function checkResponse(response) {
return response.status < 400
? response
: Promise.reject(new Error('Request Failed: ' + response.ststus))
}
// 1 point : le return & l'expression forment une ligne unique
function 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-functions
function 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 ?

  1. Parcourir une liste d’urls
  2. Appliquer une requête HTTP GET inline :
  3. Requête HTTP fetch
  4. Retourner le corps de texte de la réponse
  5. Ajouter un .then(text => console.log(text)) après chaque promesse dans textPromise
  6. 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

VS Code refactor extrayant des méthodes async de code Promise

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

Chaîne de promesses refactorisée utilisant Promise.all et map pour une meilleure lisibilité

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. ❤️

Crédit : matt-nelson-414464-unsplash.webp

Lectures connexes