Avez-vous déjà eu l'impression de faire la queue dans un café pour que JavaScript récupère votre latte ? La programmation asynchrone peut souvent ressembler à cela : plusieurs commandes traitées en même temps peuvent vous laisser attendre. Heureusement, des outils tels que Promises et async/await garantissent que le processus reste fluide et efficace, permettant à votre code de continuer à avancer sans délai.
Dans ce guide, nous expliquerons comment fonctionnent les promesses, pourquoi async/await a été introduit et comment cela simplifie l'écriture de code asynchrone. Que vous soyez un débutant essayant de comprendre ces concepts ou que vous cherchiez à savoir quand utiliser chaque approche, cet article vous aidera à maîtriser les bases.
Les promesses sont un concept fondamental en JavaScript pour gérer les opérations asynchrones. À la base, une promesse représente une valeur qui pourrait être disponible maintenant, plus tard ou jamais. Pensez-y comme au numéro de suivi d'un colis : même si vous n'avez pas encore le colis, le numéro de suivi vous donne l'assurance qu'il est en route (ou vous permet de savoir si quelque chose s'est mal passé).
S'appuyant sur le récit « maintenant, plus tard ou jamais », une promesse fonctionne en fait dans l'un des trois états suivants :
Créer et utiliser des promesses implique une API simple. Voici comment définir une promesse :
const fetchData = new Promise((resolve, reject) => { setTimeout(() => { const data = { id: 1, name: "JavaScript Basics" }; resolve(data); // Simulates a successful operation // reject("Error: Unable to fetch data"); // Simulates a failure }, 1000); });
Pour gérer le résultat, vous pouvez chaîner les méthodes .then(), .catch() et .finally() à l'objet Promise :
fetchData .then((data) => { console.log("Data received:", data); }) .catch((error) => { console.error(error); }) .finally(() => { console.log("Operation complete."); });
Le rappel dans la méthode then() est exécuté lorsque la promesse est résolue avec un résultat réussi. Le rappel dans la méthode .catch() est exécuté lorsque la promesse est résolue avec un résultat échoué, et le rappel dans la méthode enfin() est exécuté une fois la promesse résolue, quel que soit le résultat de la résolution.
Les promesses offrent une alternative plus propre aux rappels profondément imbriqués, souvent appelés « l'enfer des rappels ». Au lieu d'empiler les rappels, les promesses permettent le chaînage, ce qui rend le flux des opérations plus facile à suivre :
doTask1() .then((result1) => doTask2(result1)) .then((result2) => doTask3(result2)) .catch((error) => console.error("An error occurred:", error));
Voici à quoi ce même code aurait ressemblé s'il avait été écrit à l'aide de rappels traditionnels :
doTask1((error1, result1) => { if (error1) { console.error("An error occurred:", error1); return; } doTask2(result1, (error2, result2) => { if (error2) { console.error("An error occurred:", error2); return; } doTask3(result2, (error3, result3) => { if (error3) { console.error("An error occurred:", error3); return; } console.log("Final result:", result3); }); }); });
Déroutant, n'est-ce pas ? C'est pourquoi les promesses ont changé la donne dans les normes de codage JavaScript lors de leur introduction.
Bien que Promises ait grandement amélioré les fonctions de rappel traditionnelles, elles ne sont pas venues sans leurs propres défis. Malgré leurs avantages, ils peuvent devenir lourds dans des scénarios complexes, entraînant un code verbeux et des difficultés de débogage.
Même avec le chaînage .then(), les promesses peuvent entraîner un code encombré lorsqu'il s'agit de plusieurs opérations asynchrones. Par exemple, la gestion des opérations séquentielles avec des blocs .then() et la gestion des erreurs à l'aide de .catch() peuvent sembler répétitives et plus difficiles à suivre.
const fetchData = new Promise((resolve, reject) => { setTimeout(() => { const data = { id: 1, name: "JavaScript Basics" }; resolve(data); // Simulates a successful operation // reject("Error: Unable to fetch data"); // Simulates a failure }, 1000); });
Bien que plus propre que les rappels imbriqués, la syntaxe de chaînage est toujours détaillée, en particulier lorsqu'une logique personnalisée détaillée de gestion des erreurs est requise. De plus, oublier d'ajouter un .catch() à la fin d'une chaîne peut entraîner des échecs silencieux, rendant le débogage délicat.
De plus, les traces de pile dans Promises ne sont pas aussi intuitives que celles du code synchrone. Lorsqu'une erreur se produit, la trace de la pile peut ne pas indiquer clairement l'origine du problème dans votre flux asynchrone.
Enfin, bien que les promesses aident à réduire l'enfer des rappels, elles peuvent toujours entraîner de la complexité lorsque les tâches sont interdépendantes. Les blocs .then() imbriqués peuvent réapparaître dans certains cas d'utilisation, ramenant certains des problèmes de lisibilité qu'ils étaient censés résoudre.
La programmation asynchrone en JavaScript a fait un pas de géant avec l'introduction de async/await dans ES2017 (ES8). Construit sur Promises, async/await permet aux développeurs d'écrire du code asynchrone qui ressemble et se comporte davantage comme du code synchrone. Cela change réellement la donne en améliorant la lisibilité, en simplifiant la gestion des erreurs et en réduisant la verbosité.
Async/await est une syntaxe conçue pour rendre le code asynchrone plus facile à comprendre et à maintenir.
Le mot-clé async est utilisé pour déclarer une fonction qui renvoie toujours une promesse. Dans cette fonction, le mot-clé wait suspend l'exécution jusqu'à ce qu'une promesse soit résolue ou rejetée. Il en résulte un flux linéaire et intuitif, même pour les opérations asynchrones complexes.
Voici un exemple de la façon dont async/await simplifie le même exemple de code que vous avez vu ci-dessus :
fetchData .then((data) => { console.log("Data received:", data); }) .catch((error) => { console.error(error); }) .finally(() => { console.log("Operation complete."); });
Async/await élimine le besoin de chaînes .then(), permettant au code de circuler de manière séquentielle. Cela facilite le suivi de la logique, notamment pour les tâches qui doivent être exécutées les unes après les autres.
Avec Promises, les erreurs doivent être détectées à chaque niveau de la chaîne à l'aide de .catch(). Async/await, d'autre part, consolide la gestion des erreurs à l'aide de try/catch, réduisant ainsi les répétitions et améliorant la clarté.
Async/await produit des traces de pile plus intuitives que Promises. Lorsqu'une erreur se produit, la trace reflète la hiérarchie réelle des appels de fonction, ce qui rend le débogage moins frustrant. Dans l'ensemble, async/await semble plus « naturel » car il correspond à la façon dont le code synchrone est écrit.
Comme vous l'avez déjà vu, Async/await brille en matière de lisibilité, notamment pour les opérations séquentielles. Les promesses, avec leur chaînage .then() et .catch(), peuvent rapidement devenir verbeuses ou complexes. En revanche, le code async/wait est plus facile à suivre car il imite une structure synchrone.
Les promesses ont toujours leur place, notamment pour les tâches concurrentes. Des méthodes telles que Promise.all() et Promise.race() sont plus efficaces pour exécuter plusieurs opérations asynchrones en parallèle. Async/await peut également gérer de tels cas, mais cela nécessite une logique supplémentaire pour obtenir le même résultat.
const fetchData = new Promise((resolve, reject) => { setTimeout(() => { const data = { id: 1, name: "JavaScript Basics" }; resolve(data); // Simulates a successful operation // reject("Error: Unable to fetch data"); // Simulates a failure }, 1000); });
Bien que la gestion centralisée des erreurs avec un seul .catch() fonctionne bien pour les chaînes linéaires de promesses, il est recommandé d'utiliser des appels .catch distribués pour différents types d'erreurs entre les chaînes pour une meilleure lisibilité.
D'un autre côté, un bloc try/catch offre une structure plus naturelle pour gérer les erreurs, notamment lorsqu'il s'agit de tâches séquentielles.
En termes de performances, async/await est essentiellement équivalent à Promises puisqu'il est construit sur elles. Cependant, pour les tâches nécessitant une simultanéité, Promise.all() peut être plus efficace car il permet à plusieurs promesses de s'exécuter en parallèle, échouant rapidement si une promesse est rejetée.
Si vos tâches impliquent de nombreuses opérations simultanées, telles que la récupération simultanée de données à partir de plusieurs API, les promesses sont probablement le meilleur choix. Si votre code asynchrone n'implique pas beaucoup de chaînage, Promises serait également bien adapté dans cette situation en raison de sa simplicité.
D'un autre côté, async/await excelle dans les situations où de nombreuses tâches doivent être exécutées séquentiellement ou lorsque la lisibilité et la maintenabilité sont des priorités. Par exemple, si vous avez une série d'opérations dépendantes, telles que récupérer des données, les transformer et les enregistrer, async/await offre une structure propre et synchrone. Cela facilite le suivi du flux des opérations et simplifie la gestion centralisée des erreurs avec des blocs try/catch. Async/await est particulièrement utile pour les débutants ou les équipes donnant la priorité au code lisible.
JavaScript propose deux outils puissants pour gérer les opérations asynchrones : Promises et async/await. Les promesses ont révolutionné la façon dont les développeurs gèrent les tâches asynchrones, résolvant des problèmes tels que l'enfer des rappels et permettant le chaînage. Async/await s'appuie sur Promises, fournissant une syntaxe plus claire, plus naturelle et intuitive, en particulier pour les tâches séquentielles.
Maintenant que vous avez exploré les deux approches, vous êtes en mesure de choisir celle qui convient le mieux à vos besoins. Essayez de convertir une fonction basée sur Promise en async/wait et observez la différence de lisibilité !
Pour plus d'informations, consultez la documentation MDN Promise ou expérimentez un bac à sable de codage interactif !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!