


JavaScript asynchrone - Le parcours des rappels à l'attente asynchrone
En tant que langage monothread, JavaScript s'est toujours appuyé sur une programmation asynchrone pour gérer les tâches fastidieuses sans bloquer l'exécution du code. Au fil des années, les approches de gestion de l'asynchronicité en JavaScript ont considérablement évolué, devenant plus lisibles, plus faciles à gérer et plus faciles à raisonner. Laissez-moi vous faire voyager à travers l'histoire du JavaScript asynchrone, des rappels aux promesses d'asynchronisation/d'attente.
JavaScript synchrone : la naissance
Au début de JavaScript, avant l'adoption généralisée des rappels, la plupart du code JavaScript était écrit de manière synchrone. Le code synchrone signifie que chaque opération est exécutée l’une après l’autre, de manière bloquante. Lorsqu'une opération de longue durée était rencontrée, l'exécution de l'intégralité du script était suspendue jusqu'à ce que cette opération soit terminée.
Imaginez que vous êtes au guichet d'une gare avec un seul vendeur de billets. Vous demandez un billet et le vendeur de billets commence à traiter votre demande. Dans le modèle synchrone, vous devrez attendre au comptoir jusqu'à ce que le vendeur de billets ait fini de traiter votre demande et vous remette le billet. Pendant ce temps, personne d'autre ne peut être servi et l'ensemble de la billetterie est bloqué.
Voici un exemple de code JavaScript synchrone :
console.log("Before operation"); // Simulating a long-running operation for (let i = 0; i < 1000000000; i++) { // Performing some computation } console.log("After operation");
Dans ce code, les instructions console.log seront exécutées dans l'ordre et l'opération de longue durée (la boucle for) bloquera l'exécution du script jusqu'à ce qu'il se termine. Le message "Après opération" ne sera enregistré qu'une fois la boucle terminée.
Le problème avec le code synchrone
Bien que le code synchrone soit simple à comprendre et à raisonner, il pose plusieurs problèmes, notamment lorsqu'il s'agit d'opérations chronophages :
- Blocage de l'exécution : les opérations de longue durée bloquent l'exécution de l'intégralité du script, rendant la page Web ou l'application insensible jusqu'à la fin de l'opération.
- Mauvaise expérience utilisateur : le blocage de l'exécution peut conduire à une mauvaise expérience utilisateur, car les utilisateurs doivent attendre la fin des opérations avant d'interagir avec l'application.
- Utilisation inefficace des ressources : le code synchrone ne permet pas une utilisation efficace des ressources système, car il ne peut pas effectuer d'autres tâches en attendant la fin d'une opération.
Pour surmonter les limites du code synchrone et offrir une meilleure expérience utilisateur, des techniques de programmation asynchrone ont été introduites. La programmation asynchrone permet d'exécuter des opérations de longue durée en arrière-plan sans bloquer l'exécution du reste du code et c'est ainsi que le rappel a été introduit.
Rappels : les premiers jours
Les rappels étaient le principal moyen de gérer les opérations asynchrones. Un rappel est simplement une fonction passée en argument à une autre fonction, à exécuter ultérieurement une fois l'opération asynchrone terminée.
Imaginez que vous souhaitiez acheter un billet de train. Vous vous présentez au guichet de la gare et demandez un billet pour une destination précise. Le vendeur de billets prend en compte votre demande et vous demande d'attendre le temps de vérifier la disponibilité des places dans le train. Vous leur fournissez vos coordonnées et attendez dans la salle d’attente. Une fois que le vendeur de billets a traité votre demande et qu'une place est disponible, il vous appelle pour vous informer que votre billet est prêt à être récupéré. Dans cette analogie, vos coordonnées constituent le rappel - un moyen pour le vendeur de billets de vous avertir lorsque la tâche asynchrone (vérifier la disponibilité des sièges et émettre le billet) est terminée.
Voici comment l'analogie se rapporte aux rappels en JavaScript :
- Demander un billet de train, c'est comme appeler une fonction asynchrone qui prend un rappel comme argument.
- Fournir vos coordonnées au vendeur de billets, c'est comme transmettre une fonction de rappel à la fonction asynchrone.
- Le vendeur de billets vérifiant la disponibilité des sièges et traitant votre demande est comme une opération asynchrone en cours d'exécution.
- Le vendeur de billets qui appelle votre nom lorsque le billet est prêt est comme la fonction de rappel invoquée avec le résultat de l'opération asynchrone.
- Vous attendez dans la zone d'attente, c'est comme si le reste de l'exécution de votre code se poursuivait pendant que l'opération asynchrone était en cours de traitement.
Dans l'approche callback, vous fournissez une fonction (le callback) qui sera appelée une fois l'opération asynchrone terminée. La fonction asynchrone effectue sa tâche puis appelle le rappel avec le résultat ou l'erreur, permettant à votre code de gérer le résultat de l'opération asynchrone.
Voici un exemple d'appel API à l'aide de rappels dans Node.js :
console.log("Before operation"); // Simulating a long-running operation for (let i = 0; i < 1000000000; i++) { // Performing some computation } console.log("After operation");
Dans cet exemple, nous avons une fonction fetchData qui simule un appel API. Il prend un paramètre url et une fonction de rappel comme arguments. À l'intérieur de la fonction, nous utilisons setTimeout pour simuler un délai de 1 000 millisecondes (1 seconde) avant d'appeler la fonction de rappel.
La fonction de rappel suit la convention commune consistant à accepter une erreur comme premier argument (err) et les données comme deuxième argument (data). Dans cet exemple, nous simulons un appel d'API réussi en définissant l'erreur sur null et en fournissant un exemple d'objet de données.
Pour utiliser la fonction fetchData, nous l'appelons avec une URL et une fonction de rappel. Dans la fonction de rappel, nous vérifions d'abord si une erreur s'est produite en vérifiant l'argument err. Si une erreur existe, nous l'enregistrons sur la console à l'aide de console.error et revenons pour arrêter la poursuite de l'exécution.
Si aucune erreur ne s'est produite, nous enregistrons les données reçues sur la console à l'aide de console.log.
Lorsque vous exécutez ce code, il simulera un appel API asynchrone. Après un délai d'1 seconde, la fonction de rappel sera invoquée et le résultat sera enregistré sur la console :
{ identifiant : 1, nom : 'John Doe' }
Cet exemple montre comment les rappels peuvent être utilisés pour gérer les appels d'API asynchrones. La fonction de rappel est passée en argument à la fonction asynchrone (fetchData) et elle est invoquée une fois l'opération asynchrone terminée, soit avec une erreur, soit avec les données résultantes.
Bien que les rappels aient fait le travail, ils présentaient plusieurs inconvénients :
- Callback Hell/Pyramide of Doom : L'imbrication de plusieurs opérations asynchrones a conduit à un code profondément imbriqué et indenté, le rendant difficile à lire et à maintenir.
- Gestion des erreurs : La gestion des erreurs à chaque niveau d'imbrication était fastidieuse et conduisait souvent à un code répétitif.
- Manque de lisibilité : La nature non linéaire des rappels rendait le code plus difficile à suivre et à raisonner.
Promesses : un pas en avant
Pour relever les défis liés aux rappels, des promesses ont été introduites dans ES6 (ECMAScript 2015). Une promesse représente l'achèvement ou l'échec éventuel d'une opération asynchrone et vous permet d'enchaîner des opérations entre elles.
Pensez à une promesse comme à un billet de train. Lorsque vous achetez un billet de train, celui-ci représente une promesse de la compagnie ferroviaire que vous pourrez monter à bord du train et atteindre votre destination. Le billet contient des informations sur le train, telles que l'heure de départ, l'itinéraire et le numéro de siège. Une fois que vous avez le billet, vous pouvez attendre l'arrivée du train, et lorsqu'il est prêt à embarquer, vous pouvez monter dans le train avec votre billet.
Dans cette analogie, le billet de train est la promesse. Il représente l’aboutissement éventuel d’une opération asynchrone (le voyage en train). Vous conservez le ticket (l'objet de promesse) jusqu'à ce que le train soit prêt (l'opération asynchrone est terminée). Une fois la promesse résolue (le train arrive), vous pouvez utiliser le billet pour monter à bord du train (accéder à la valeur résolue).
Voici comment l'analogie est liée aux promesses en JavaScript :
- Acheter le billet de train, c'est comme appeler une fonction asynchrone qui renvoie une promesse.
- Le billet de train lui-même est l'objet de la promesse, représentant le résultat futur de l'opération asynchrone.
- Attendre l'arrivée du train, c'est comme attendre que la promesse soit résolue ou rejetée.
- Monter à bord du train avec le billet, c'est comme utiliser .then() pour accéder à la valeur résolue de la promesse.
- Si le train est annulé (une erreur se produit), c'est comme si la promesse était rejetée, et vous la géreriez avec .catch().
Les promesses fournissent un moyen structuré de gérer les opérations asynchrones, vous permettant d'enchaîner plusieurs opérations et de gérer les erreurs de manière plus gérable, tout comme la façon dont un billet de train vous aide à organiser et à gérer votre voyage en train.
Voici un exemple d'appel d'API à l'aide de promesses :
console.log("Before operation"); // Simulating a long-running operation for (let i = 0; i < 1000000000; i++) { // Performing some computation } console.log("After operation");
Dans ce code, la fonction fetchData renvoie une promesse. Le constructeur de promesse prend une fonction qui accepte deux arguments : résoudre et rejeter. Ces fonctions sont utilisées pour contrôler l'état de la promesse.
Dans le constructeur de promesse, nous simulons un appel API en utilisant setTimeout, comme dans l'exemple précédent. Cependant, au lieu d'invoquer une fonction de rappel, nous utilisons les fonctions de résolution et de rejet pour gérer le résultat asynchrone.
Si une erreur se produit (dans cet exemple, nous la simulons en vérifiant la variable d'erreur), nous appelons la fonction de rejet avec l'erreur, indiquant que la promesse doit être rejetée.
Si aucune erreur ne se produit, nous appelons la fonction de résolution avec les données, indiquant que la promesse doit être résolue avec les données reçues.
Pour utiliser la fonction fetchData, nous enchaînons les méthodes .then() et .catch() à l'appel de fonction. La méthode .then() est utilisée pour gérer la valeur résolue de la promesse, tandis que la méthode .catch() est utilisée pour gérer les erreurs qui peuvent survenir.
Si la promesse est résolue avec succès, la méthode .then() est invoquée avec les données résolues et nous les enregistrons dans la console à l'aide de console.log.
Si une erreur se produit et que la promesse est rejetée, la méthode .catch() est invoquée avec l'objet err et nous l'enregistrons sur la console à l'aide de console.error.
L'utilisation de promesses offre un moyen plus structuré et plus lisible de gérer les opérations asynchrones par rapport aux rappels. Les promesses vous permettent d'enchaîner plusieurs opérations asynchrones à l'aide de .then() et de gérer les erreurs de manière plus centralisée à l'aide de .catch().
Promesses améliorées lors des rappels de plusieurs manières :
- Chaînage : les promesses vous permettaient d'enchaîner plusieurs opérations asynchrones ensemble à l'aide de .then, rendant le code plus lisible et plus facile à suivre.
- Gestion des erreurs : Promises a fourni une méthode .catch pour gérer les erreurs de manière plus centralisée et rationalisée.
- Lisibilité : les promesses ont fait ressembler le code asynchrone davantage à du code synchrone, améliorant ainsi la lisibilité.
Cependant, les promesses avaient encore certaines limites. L'enchaînement de plusieurs promesses pouvait toujours conduire à un code profondément imbriqué, et la syntaxe n'était pas aussi claire qu'elle pourrait l'être.
Async/Await : l'approche moderne
Async/await, introduit dans ES8 (ECMAScript 2017), repose sur des promesses et fournit une manière plus synchrone d'écrire du code asynchrone.
Avec async/await, vous pouvez écrire du code asynchrone qui ressemble et se comporte comme du code synchrone. C'est comme si vous aviez un assistant personnel qui se rend au guichet à votre place. Vous attendez simplement le retour de votre assistant avec le billet, et une fois qu'il l'a fait, vous pouvez continuer votre voyage.
Voici un exemple d'appel API à l'aide de async/await :
console.log("Before operation"); // Simulating a long-running operation for (let i = 0; i < 1000000000; i++) { // Performing some computation } console.log("After operation");
Dans ce code, nous avons une fonction asynchrone appelée fetchData qui prend un paramètre url représentant le point de terminaison de l'API. À l'intérieur de la fonction, nous utilisons un bloc try/catch pour gérer les erreurs pouvant survenir lors de la requête API.
Nous utilisons le mot-clé wait avant la fonction fetch pour suspendre l'exécution jusqu'à ce que la promesse renvoyée par fetch soit résolue. Cela signifie que la fonction attendra que la requête API soit terminée avant de passer à la ligne suivante.
Une fois la réponse reçue, nous utilisons wait réponse.json() pour analyser le corps de la réponse au format JSON. Il s'agit également d'une opération asynchrone, nous utilisons donc wait pour attendre la fin de l'analyse.
Si la requête API et l'analyse JSON réussissent, les données sont renvoyées par la fonction fetchData.
Si une erreur se produit lors de la requête API ou de l'analyse JSON, elle est détectée par le bloc catch. Nous enregistrons l'erreur sur la console à l'aide de console.error et renvoyons l'erreur à l'aide de throw err pour la propager à l'appelant.
Pour utiliser la fonction fetchData, nous avons une fonction asynchrone appelée main. Dans main, nous spécifions l'URL du point de terminaison de l'API à partir duquel nous souhaitons récupérer les données.
Nous utilisons wait fetchData(url) pour appeler la fonction fetchData et attendons qu'elle renvoie les données. Si la requête API réussit, nous enregistrons les données reçues dans la console.
Si une erreur se produit lors de la requête API, elle est détectée par le bloc catch dans la fonction principale. Nous enregistrons l'erreur sur la console en utilisant console.error.
Enfin, nous appelons la fonction principale pour démarrer l'exécution du programme.
Lorsque vous exécutez ce code, il effectuera une requête API asynchrone vers l'URL spécifiée à l'aide de la fonction fetch. Si la demande réussit, les données reçues seront enregistrées sur la console. Si une erreur se produit, elle sera également détectée et enregistrée.
L'utilisation de async/await avec la fonction fetch fournit un moyen propre et lisible de gérer les requêtes API asynchrones. Il vous permet d'écrire du code asynchrone qui ressemble et se comporte comme du code synchrone, ce qui le rend plus facile à comprendre et à maintenir.
Async/await offre plusieurs avantages :
- Code concis : Async/await vous permet d'écrire du code asynchrone qui ressemble à du code synchrone, le rendant plus concis et lisible.
- Gestion des erreurs : Async/await utilise des blocs try/catch pour la gestion des erreurs, ce qui est une manière plus familière et intuitive de gérer les erreurs par rapport à .catch avec des promesses.
- Lisibilité : Async/await rend le code asynchrone plus facile à comprendre et à raisonner, en particulier pour les développeurs familiarisés avec la programmation synchrone.
Conclusion
En conclusion, l'évolution du JavaScript asynchrone, des rappels aux promesses d'async/wait, a été un voyage vers un code asynchrone plus lisible, gérable et maintenable. Chaque étape s'appuie sur la précédente, corrigeant les limites et améliorant l'expérience du développeur.
Aujourd'hui, async/await est largement utilisé et est devenu le moyen préféré pour gérer les opérations asynchrones en JavaScript. Il permet aux développeurs d'écrire du code asynchrone propre, concis et facile à comprendre, ce qui en fait un outil précieux dans la boîte à outils de chaque développeur JavaScript.
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!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds











Python convient plus aux débutants, avec une courbe d'apprentissage en douceur et une syntaxe concise; JavaScript convient au développement frontal, avec une courbe d'apprentissage abrupte et une syntaxe flexible. 1. La syntaxe Python est intuitive et adaptée à la science des données et au développement back-end. 2. JavaScript est flexible et largement utilisé dans la programmation frontale et côté serveur.

Les principales utilisations de JavaScript dans le développement Web incluent l'interaction client, la vérification du formulaire et la communication asynchrone. 1) Mise à jour du contenu dynamique et interaction utilisateur via les opérations DOM; 2) La vérification du client est effectuée avant que l'utilisateur ne soumette les données pour améliorer l'expérience utilisateur; 3) La communication de rafraîchissement avec le serveur est réalisée via la technologie AJAX.

L'application de JavaScript dans le monde réel comprend un développement frontal et back-end. 1) Afficher les applications frontales en créant une application de liste TODO, impliquant les opérations DOM et le traitement des événements. 2) Construisez RestulAPI via Node.js et Express pour démontrer les applications back-end.

Comprendre le fonctionnement du moteur JavaScript en interne est important pour les développeurs car il aide à écrire du code plus efficace et à comprendre les goulots d'étranglement des performances et les stratégies d'optimisation. 1) Le flux de travail du moteur comprend trois étapes: analyse, compilation et exécution; 2) Pendant le processus d'exécution, le moteur effectuera une optimisation dynamique, comme le cache en ligne et les classes cachées; 3) Les meilleures pratiques comprennent l'évitement des variables globales, l'optimisation des boucles, l'utilisation de const et de locations et d'éviter une utilisation excessive des fermetures.

Python et JavaScript ont leurs propres avantages et inconvénients en termes de communauté, de bibliothèques et de ressources. 1) La communauté Python est amicale et adaptée aux débutants, mais les ressources de développement frontal ne sont pas aussi riches que JavaScript. 2) Python est puissant dans les bibliothèques de science des données et d'apprentissage automatique, tandis que JavaScript est meilleur dans les bibliothèques et les cadres de développement frontaux. 3) Les deux ont des ressources d'apprentissage riches, mais Python convient pour commencer par des documents officiels, tandis que JavaScript est meilleur avec MDNWEBDOCS. Le choix doit être basé sur les besoins du projet et les intérêts personnels.

Les choix de Python et JavaScript dans les environnements de développement sont importants. 1) L'environnement de développement de Python comprend Pycharm, Jupyternotebook et Anaconda, qui conviennent à la science des données et au prototypage rapide. 2) L'environnement de développement de JavaScript comprend Node.js, VScode et WebPack, qui conviennent au développement frontal et back-end. Le choix des bons outils en fonction des besoins du projet peut améliorer l'efficacité du développement et le taux de réussite du projet.

C et C jouent un rôle essentiel dans le moteur JavaScript, principalement utilisé pour implémenter des interprètes et des compilateurs JIT. 1) C est utilisé pour analyser le code source JavaScript et générer une arborescence de syntaxe abstraite. 2) C est responsable de la génération et de l'exécution de bytecode. 3) C met en œuvre le compilateur JIT, optimise et compile le code de point chaud à l'exécution et améliore considérablement l'efficacité d'exécution de JavaScript.

JavaScript est largement utilisé dans les sites Web, les applications mobiles, les applications de bureau et la programmation côté serveur. 1) Dans le développement de sites Web, JavaScript exploite DOM avec HTML et CSS pour réaliser des effets dynamiques et prend en charge des cadres tels que JQuery et React. 2) Grâce à la réactnative et ionique, JavaScript est utilisé pour développer des applications mobiles multiplateformes. 3) Le cadre électronique permet à JavaScript de créer des applications de bureau. 4) Node.js permet à JavaScript d'exécuter le côté du serveur et prend en charge les demandes simultanées élevées.
