Maîtriser le débogage JavaScript dans les outils de développement modernes

Contrôle du flux d'exécution

L'utilisation de points d'arrêt permet de suspendre l'exécution du code pour analyser l'état de l'application. Lorsque l'exécution est suspendue, le débogueur évalue toutes les variables, constantes et objets de la fonction courante, affichant souvent les valeurs directement en ligne dans l'éditeur. Vous pouvez également interrroger ces valeurs via la console.

Navigation pas à pas

Une fois le code en pause, vous pouvez inspecter le flux de contrôle expression par expression.

  • Sauter (Step Over) : Exécute la ligne courante sans entrer dans les fonctions appelées. Utile lorsque la fonction appelée n'est pas pertinente pour le bug.
  • Entrer dans (Step In to) : Entre dans la fonction appelée sur la ligne courante pour inspecter son exécution interne.
  • Sortir de (Step Out) : Termine l'exécution de la fonction courante et suspend l'exécution à la ligne suivant l'appel de cette fonction.

Considérez l'exemple suivant pour illustrer ces concepts :

function processUserProfile() {
  let userId = generateId();
  let profile = fetchProfile(); // Point d'arrêt A
  renderProfile(profile); // Point D
}

function fetchProfile() {
  let data = api.firstName + ' ' + api.lastName; // Point B
  return data; // Point C
}

Si vous êtes en pause au point A, utiliser Sauter exécutera B et C, puis s'arrêtera en D. Utiliser Entrer dans vous mènera au point B. Si vous êtes au point B, Sortir de terminera la fonction et s'arrêtera en D.

Exécution ciblée et reprise

Pour éviter de parcourir manuellement de longues fonctions, faites un clic droit sur une ligne et sélectionnez l'option pour exécuter le code jusqu'à cet endroit. Pour reprendre l'exécution normale jusqu'au prochain point d'arrêt, utilisez l'icône de reprise. Si vous souhaitez ignorer tous les points d'arrêt restants, maintenez l'icône de reprise et choisissez l'option de forçage.

Inspection de l'état et de la pile d'appels

Portées et surveillance

Le panneau des portées (Scope) permet d'inspecter et de modifier les variables locales, les fermetures (closures) et les variables globales. Les valeurs peuvent être modifiées en double-cliquant dessus. Le panneau d'espionnage (Watch) permet d'ajouter des expressions JavaScript personnalisées dont les valeurs seront évaluées à chaque pas.

Pile d'appels et redémarrage de trames

La pile d'appels (Call Stack) retrace l'historique des fonctions ayant conduit à l'état actuel. Vous pouvez cliquer sur une trame pour y naviguer. Une fonctionnalité puissante est le redémarrage d'une trame (Restart frame), qui relance l'exécution de la fonction courante sans redémarrer toute l'application.

Analysons ce comportement avec cet exemple :

function initializeCounter(base) {
    console.log(base);
    incrementCounter(base);
}

function incrementCounter(current) {
    current += 5;
    console.log(current);
    debugger;
}

initializeCounter(10);

L'exécution s'arrête sur le debugger. Si vous redémarrez la trame de incrementCounter et avancez, la valeur de current continuera d'augmenter (15, 20, etc.) car le redémarrage d'une trame ne réinitialise pas les paramètres passés ; il replace simplement le pointeur d'exécution au début de la fonction. En revanche, redémarrer la trame de initializeCounter réinitialisera la valeur à 10, car les primitives en JavaScript sont passées par valeur.

Contextes asynchrones et threads

Lors du débogage de Web Workers ou de Service Workers, vous pouvez basculer entre les différents contextes d'exécution via le panneau des threads. De plus, si le framework utilisé supporte l'API console.createTask(), les outils de développement peuvent lier les opérations asynchrones pour afficher une pile d'appels complète incluant les trames asynchrones.

Organisation et modification du code

Liste d'ignorés et arborescence

Pour se concentrer sur son propre code, il est possible d'ajouter des scripts tiers ou des bibliothèques à la liste d'ignorés (Ignore List). Ces scripts seront masqués dans la pile d'appels et le pas à pas ne rentrera pas dans leurs fonctions.

function executeTask() {
  setup();
  externalLib.process(); // Ajouté à la liste d'ignorés
  finalize();
}

Dans l'arborescence des fichiers, les outils modernes permettent de séparer les fichiers "rédigés" (générés à partir des sources maps) des fichiers "déployés" (minifiés et lus par le navigateur), facilitant ainsi la navigation dans les projets utilisant des bundlers comme Webpack ou Vite.

Modification en direct (Live Edit)

Il est possible de modifier le code JavaScript directement dans l'éditeur des outils de développement et d'appliquer les changements à la volée. Depuis les versions récentes, vous pouvez même modifier une fonction actuellement en pause. Cependant, cela s'accompagne de restrictions : vous ne pouvez modifier que la fonction au sommet de la pile d'appels, et le débogueur redémarrera automatiquement cette fonction.

Exemple de correction à la volée :

// Avant modification
let priceA = "10.5";
let priceB = "20.5";
let total = priceA + priceB; // Concaténation de chaînes incorrecte

// Après modification en direct
let total = parseFloat(priceA) + parseFloat(priceB); // Addition numérique correcte

Fragments de code et utilitaires

Les fragments (Snippets) permettent de stocker et d'exécuter des scripts de débogage récurrents directement dans l'environnement de développement. L'éditeur offre également des fonctionnalités standard telles que le pliage des blocs de code, la mise en forme des fichiers minifiés via le bouton de formatage, et la recherche/remplacement de texte avec support des expressions régulières.

Étiquettes: JavaScript DevTools debugging chrome-devtools breakpoints

Publié le 12 juillet à 22h38