Introduction
Une fonctionnalité puissante qui rend JavaScript unique est sa capacité à fonctionner de manière asynchrone via des fonctions de rappel. L'attribution de rappels asynchrones vous permet d'écrire du code basé sur des événements, mais elle facilite également le suivi des bugs, car le JavaScript ne s'exécute pas de manière linéaire.
Heureusement, dans les outils pour les développeurs Chrome, vous pouvez désormais afficher la pile d'appels complète des rappels JavaScript asynchrones.
Une fois que vous aurez activé la fonctionnalité de pile d'appel asynchrone dans les outils de développement, vous pourrez voir l'état de votre application Web à différents moments. Parcourir la trace complète de la pile pour certains écouteurs d'événements setInterval
, setTimeout
, XMLHttpRequest
, promesses, requestAnimationFrame
, MutationObservers
, etc.
Lorsque vous parcourez la trace de la pile, vous pouvez également analyser la valeur de n'importe quelle variable à ce moment précis de l'exécution de l'environnement d'exécution. C'est comme une machine à remonter le temps pour les expressions de votre montre !
Activons cette fonctionnalité et examinons quelques-uns de ces scénarios.
Activer le débogage asynchrone dans Chrome
Testez cette nouvelle fonctionnalité en l'activant dans Chrome. Accédez au panneau Sources des outils pour les développeurs Chrome Canary.
À côté du panneau Call Stack (Pile d'appel) sur la droite, une nouvelle case à cocher pour "Async" apparaît. Cochez ou décochez la case pour activer ou désactiver le débogage asynchrone (même si cette option est activée, vous ne souhaiterez peut-être plus la désactiver).
Enregistrer les événements de minuteur différés et les réponses XHR
Vous avez probablement déjà vu ce qui suit dans Gmail:
En cas de problème lors de l'envoi de la requête (le serveur rencontre des problèmes ou des problèmes de connectivité réseau côté client), Gmail tente automatiquement de renvoyer le message après un court délai d'expiration.
Pour voir comment les piles d'appels asynchrones peuvent nous aider à analyser les événements de minuteur retardés et les réponses XHR, j'ai recréé ce flux avec un exemple Gmail fictif. Le code JavaScript complet est disponible via le lien ci-dessus, mais le flux est le suivant:
En consultant uniquement le panneau "Call Stack" (Pile d'appel) des versions précédentes des outils de développement, un point d'arrêt dans postOnFail()
vous donnerait peu d'informations sur l'origine de l'appel de postOnFail()
. Observez la différence lorsque vous activez les piles asynchrones:
Lorsque les piles d'appels asynchrones sont activées, vous pouvez afficher l'ensemble de la pile d'appel pour voir facilement si la requête a été lancée à partir de submitHandler()
(qui se produit après un clic sur le bouton d'envoi) ou de retrySubmit()
(qui se produit après un retard de setTimeout()
):
Observer les expressions de manière asynchrone
Lorsque vous parcourez la pile d'appels complète, vos expressions surveillées sont également mises à jour pour refléter l'état dans lequel elles se trouvaient à ce moment-là.
Évaluer le code à partir d'anciens niveaux d'accès
En plus de simplement surveiller les expressions, vous pouvez interagir avec le code des champs d'application précédents directement dans le panneau JavaScript des outils de développement.
Imaginez que vous êtes le Dr qui et que vous avez besoin d'un peu d'aide pour comparer l'horloge d'avant votre arrivée au Tardis à aujourd'hui. La console DevTools vous permet d'évaluer, de stocker et d'effectuer facilement des calculs sur des valeurs à partir de différents points d'exécution.
En restant dans les outils de développement pour manipuler vos expressions, vous gagnerez du temps, car vous n'aurez pas à revenir au code source, à apporter des modifications et à actualiser le navigateur.
Des résolutions de promesses enchaînées Unravel
Si vous pensiez qu'il était difficile de décomposer l'ancien flux Gmail sans la fonctionnalité de pile d'appel asynchrone activée, imaginez à quel point cela serait plus difficile avec des flux asynchrones plus complexes tels que les promesses enchaînées ? Reprenons le dernier exemple du tutoriel de Jake Archibald sur les promesses JavaScript.
Voici une petite animation permettant de parcourir les piles d'appels dans l'exemple async-best-example.html de Jake.
Obtenez des informations sur vos animations Web
Examinons plus en détail les archives HTML5Rocks. Vous souvenez-vous de la série Leaner, Meaner, Faster Animations with requestAnimationFrame de Paul Lewis ?
Ouvrez la démonstration requestAnimationFrame et ajoutez un point d'arrêt au début de la méthode update() (autour de la ligne 874) de post.html. Avec les piles d'appels asynchrones, nous obtenons beaucoup plus d'informations sur requestAnimationFrame, y compris la possibilité de revenir au rappel de l'événement de défilement.
Retrouver les mises à jour DOM lors de l'utilisation de MutationObserver
MutationObserver
nous permet d'observer les modifications dans le DOM. Dans cet exemple simple, lorsque vous cliquez sur le bouton, un nouveau nœud DOM est ajouté à <div class="rows"></div>
.
Ajoutez un point d'arrêt dans nodeAdded()
(ligne 31) dans demo.html. Lorsque les piles d'appels asynchrones sont activées, vous pouvez maintenant renvoyer la pile d'appel via addNode()
jusqu'à l'événement de clic initial.
Conseils pour déboguer JavaScript dans les piles d'appels asynchrones
Nommer vos fonctions
Si vous avez tendance à attribuer tous vos rappels en tant que fonctions anonymes, vous pouvez leur attribuer un nom pour faciliter l'affichage de la pile d'appels.
Prenons l'exemple d'une fonction anonyme comme celle-ci:
window.addEventListener('load', function() {
// do something
});
Donnez-lui un nom tel que windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
Lorsque l'événement de chargement se déclenche, il apparaît dans la trace de la pile des outils de développement avec son nom de fonction au lieu de l'énigmatique (fonction anonyme). Il est ainsi beaucoup plus facile de voir d'un coup d'œil ce qui se passe dans votre trace de la pile.
En savoir plus
Pour récapituler, voici tous les rappels asynchrones dans lesquels les outils de développement afficheront la pile d'appel complète:
- Minuteurs : revenez à l'endroit où
setTimeout()
ousetInterval()
a été initialisé. - XHR : revenez à l'endroit où
xhr.send()
a été appelé. - Images d'animation : revenez à l'endroit où
requestAnimationFrame
a été appelé. - Promesses : revenez là où une promesse a été résolue.
- Object.observe : revenez à l'endroit où le rappel de l'observateur était initialement lié.
- MutationObservers : revenez à l'endroit où l'événement d'observateur de mutation a été déclenché.
- window.postMessage(): suivez les appels de messagerie au sein du processus.
- DataTransferItem.getAsString()
- API FileSystem
- IndexedDB
- WebSQL
- Événements DOM éligibles via
addEventListener()
: revenez à l'endroit où l'événement a été déclenché. Pour des raisons de performances, tous les événements DOM ne sont pas éligibles à la fonctionnalité des piles d'appels asynchrones. Voici quelques exemples d'événements actuellement disponibles: "scroll", "hashchange" et "selectionchange". - Événements multimédias via
addEventListener()
: revenez à l'endroit où l'événement a été déclenché. Les événements multimédias disponibles incluent les événements audio et vidéo (par exemple, "play", "pause", "ratechange"), les événements WebRTC MediaStreamTrackList (par exemple, "addtrack", "removetrack") et les événements MediaSource (par exemple, "sourceopen").
La possibilité de voir la trace de la pile complète de vos rappels JavaScript devrait vous faciliter la tâche. Cette fonctionnalité des outils de développement est particulièrement utile lorsque plusieurs événements asynchrones se produisent les uns par rapport aux autres ou si une exception non détectée est générée depuis un rappel asynchrone.
Essayez-le dans Chrome. Si vous avez des commentaires sur cette nouvelle fonctionnalité, envoyez-nous un message sur l'outil de suivi des bugs des outils pour les développeurs Chrome ou dans le groupe des outils pour les développeurs Chrome.