Déboguer votre code (partie 1/3)

Créer des scripts paraît facile au premier abord, mais on finit toujours par tomber sur le même problème : notre code ne fonctionne pas ! On peut alors dire qu'il y a un bug, en clair il y a une erreur dans le code qui fait qu'il s'exécute mal ou ne s'exécute tout simplement pas.

Dans ce chapitre, nous allons commencer à étudier quels sont les différents bugs que l'on peut généralement rencontrer en JavaScript et surtout comment les résoudre. Pour cela, nous allons utiliser les kits de développement fournis avec n'importe quel navigateur digne de ce nom. Plus particulièrement, nous allons nous pencher sur ceux de Chrome et de Firefox qui sont sensiblement similaires.

En quoi consiste le débogage ?

Les bugs

Avant de parler de débogage, intéressons-nous d'abord aux bugs. Ces derniers sont des erreurs humaines que vous avez laissées dans votre code ; ils ne sont jamais le fruit du hasard. N'essayez pas de vous dire « Je n'en ferai pas », il n'est pas possible de rester concentré au point de ne jamais vous tromper sur plusieurs centaines de lignes de code ! Et même si un code de 100 lignes venait à fonctionner du premier coup, on finira au final par se dire que c'est trop beau pour être vrai et on va donc partir à la recherche de bugs qui n'existent au final peut-être pas. :-°

Il existe deux types principaux de bugs : ceux que l'interpréteur JavaScript saura vous signaler car ce sont des fautes de syntaxe, et ceux que l'interpréteur ne verra pas car ce sont des erreurs dans votre algorithme.

Pour faire simple, voici un bug syntaxique :

va myVar = 'test; // Le mot-clé « var » est mal orthographié et il manque une apostrophe

Et maintenant un bug algorithmique :

// On veut afficher la valeur 6 avec les nombres 3 et 2
var myVar = 3 + 2;
// Mais on obtient 5 au lieu de 6 car on a fait une addition au lieu d'une multiplication

Il faut bien se mettre en tête que l'interpréteur JavaScript se fiche bien des valeurs retournées par votre code, il veut exécuter le code et c'est tout. Voici la différence entre le caractère syntaxique et algorithmique d'une erreur : la première empêche le code de s'exécuter tandis que la seconde ne pose aucun problème d'exécution. Pourtant, les deux perturbent le bon déroulement de votre script.

Le débogage

Comme son nom l'indique, cette technique consiste à supprimer les bugs qui existent dans votre code. Pour chaque type de bug vous avez plusieurs solutions bien particulières.

Les bugs syntaxiques sont les plus simples à résoudre, car l'interpréteur JavaScript vous signalera généralement l'endroit où l'erreur est apparue, cette signalisation peut être consultée dans la console de votre navigateur. Vous verrez comment vous servir de la console un peu plus loin.

En ce qui concerne les bugs algorithmiques, là il va falloir faire travailler votre cerveau et chercher par vous-mêmes où vous avez bien pu vous tromper. La méthode la plus simple consiste à remonter les couches de votre code pour trouver à quel endroit s'est produit l'erreur.

Par exemple, si vous avez un calcul qui affiche une mauvaise valeur, vous allez immédiatement vérifier ce calcul. Si ce calcul n'est pas en cause mais qu'il fait appel à des variables, alors vous allez vérifier la valeur de chacune de ces variables, etc. De fil en aiguille vous allez parvenir à déboguer votre code.

Les kits de développement et leur console

Aujourd'hui, chaque navigateur un tant soit peu récent possède un kit de développement. C'est le cas de Chrome, Firefox, Internet Explorer, Safari, Opera, etc... Sans même parler des déclinaisons mobiles ! Ces kits nous permettent de déboguer efficacement nos codes, que ce soit pour détecter des erreurs syntaxiques, afficher un grand nombre de valeurs dans la console, consulter le code HTML généré par du code, analyser des requêtes HTTP (entre autres) effectuées par le navigateur, mesurer les performances de votre code, et bien d'autres choses encore !

Comme il n'est pas possible de parler des fonctionnalités de chaque kit de développement, nous allons nous concentrer sur les plus utilisés, ceux de Chrome et de Firefox. Concrètement, nous parlerons généralement de Chrome car le fonctionnement est, dans l'ensemble, identique sur Firefox, mais si ce dernier venait à avoir un fonctionnement différent sur un point, nous vous en ferons part.

Bien, à quoi ressemble un kit de développement ? Voici ceux de nos deux navigateurs favoris :

Firefox 29
Chrome 34
Firefox 29
Firefox 29

Durant ce chapitre, nous allons essentiellement nous servir de la console ainsi que de quelques autres fonctionnalités, nous étudierons d'autres outils plus tard dans le cours. Pour ouvrir votre kit de développement, appuyez sur la touche F12 ou bien, pour les utilisateurs d'OS X, sur la combinaison de touches Cmd + Alt + I. Vous verrez alors apparaître le kit de développement en bas de votre navigateur. Si vous n'y êtes pas déjà, ouvrez la console en cliquant sur l'onglet correspondant en haut du kit.

Maintenant que notre console est ouverte, que pouvons nous faire avec ? Beaucoup de choses, mais intéressons d'abord à la signalisation des erreurs syntaxiques. Créons un code syntaxiquement faux :

// Ici nous créons une fonction JavaScript, avec quelques erreurs de syntaxe.
functin test() {
alert('Hello !');

Et incluons-le dans notre code HTML :

<script src="votre-fichier.js"></script>

Essayer le code

Maintenant, affichez cette page dans votre navigateur et allez consulter la console, vous devriez voir l'erreur suivante affichée :

Vous pouvez voir une ligne écrite en rouge. Ce qui est important c'est le terme SyntaxError qui mentionne une erreur syntaxique, le texte qui suit n'est qu'une indication sur ce qui a bien pu provoquer cette erreur, ce n'est généralement pas utile de le lire d'autant plus que chaque navigateur peut fournir une indication relativement différente. Par exemple, Firefox indique « SyntaxError: missing ; before statement ».

À droite de ce texte, vous pouvez voir le nom du fichier concerné ainsi que la ligne de code, vous pouvez cliquer dessus et votre navigateur vous amènera directement sur la ligne qui pose problème :

 

Notre code contient deux erreurs, pourquoi n'y en a-t-il qu'une d'affichée ?

Tout simplement parce que l'interpréteur JavaScript s'arrête sur la première erreur rencontrée. Essayez de rectifier l'erreur actuellement indiquée, vous verrez que le navigateur vous affichera alors l'erreur suivante sur Chrome : « Uncaught SyntaxError: Unexpected end of input ». Firefox, lui, est un peu plus clair sur ce point : « SyntaxError: missing } after function body ».

Notons que la console vous permet aussi de repérer d'autres erreurs qui ne sont pas forcément liées au JavaScript, telles que des images manquantes, par exemple. Dans l'ensemble, si le comportement de votre page web n'est pas conforme à ce à quoi vous vous attendiez, consultez toujours la console avant de demander de l'aide à qui que ce soit, vous trouverez généralement la source de votre problème indiquée dans la console.

Aller plus loin avec la console

La console est un formidable outil qui permet de faire bien plus que de simplement vous lister les erreurs sur votre page. Remplaçons le code JavaScript de notre page de test par celui-ci :

for (var i = 0; i < 10; i++) {
// On affiche les valeurs de notre boucle dans la console.
console.log('La valeur de notre boucle est : ' + i);
}

Essayer le code

Une fois ce code exécuté, vous devriez voir écrit ceci dans la console :

La valeur de notre boucle est : 0
La valeur de notre boucle est : 1
La valeur de notre boucle est : 2
La valeur de notre boucle est : 3
La valeur de notre boucle est : 4
La valeur de notre boucle est : 5
La valeur de notre boucle est : 6
La valeur de notre boucle est : 7
La valeur de notre boucle est : 8
La valeur de notre boucle est : 9 

La méthodeconsole.log()vous permet d'afficher la valeur d'une variable sans bloquer l'exécution de votre code, contrairement à la fonctionalert(). Mais l'intérêt de cette méthode va beaucoup plus loin car elle permet de visualiser le contenu des objets de manière relativement pratique, essayez donc ce code :

// On crée un objet basique.
var helloObject = {
english: 'Hello',
french: 'Bonjour',
spanish: 'Hola'
};
// Et on l'affiche.
console.log(helloObject);
// Tant qu'à faire, on affiche aussi un tableau.
var helloArray = ['Hello', 'Bonjour', 'Hola'];
console.log(helloArray);

Essayer le code

Nous obtenons alors ceci :

Là où la fonctionalert()aurait affiché « [object Object] »,console.log()affiche le contenu de l'objet, ce qui est nettement plus pratique. Cette méthode est utilisable sur tous les types de variables et pourra vous aider de nombreuses fois !

En plus de la méthodelog(), l'objetconsoleen propose d'autres qui permettent de modifier la manière dont vous affichez vos valeurs, vous pouvez ainsi choisir d'émettre des alertes ou des erreurs avec les méthodeswarn()eterror(), vous pouvez grouper des lignes de résultats avecgroup()etgroupEnd()(c'est parfois extrêmement pratique). La liste complète des méthodes a été réalisée par Google, vous pouvez la consulter sur la page web dédiée .

Cependant, gardez bien à l'idée que toutes ces méthodes sont faites pour déboguer votre code et n'ont rien à faire dans votre code une fois votre site mis en ligne !

Restons dans l'onglet « Console » de notre kit de développement. Si vous regardez en bas, vous devriez voir une ligne qui commence par un chevron bleu, il est possible d'y écrire directement du code, voyons ça avec un exemple simple :

// On déclare une variable contenant un texte quelconque.
var myVar = 'Hello';
// Toutes les secondes, on affiche le contenu de cette variable dans la console.
setInterval(function() {
console.log(myVar);
}, 1000);

Essayer le code

Ne vous préoccupez pas trop de la manière dont fonctionne ce code, la fonctionsetInterval()sera expliquée plus tard dans ce cours, mais dans l'immédiat elle nous sert bien d'exemple.

Une fois le code exécuté, vous allez voir le contenu de la variable apparaître toutes les secondes dans la console. Essayez maintenant d'écriremyVar = 'Bonjour';dans la console et de valider avec la touche Entrée, le texte affiché devrait alors changer. Cet exemple consiste à vous montrer que vous pouvez, grâce à la console, agir sur votre code pendant son exécution ! Cependant, prenez garde, la console ne peut agir que sur les variables qui sont globales !

Utiliser les points d'arrêt

Lorsque vous développez, il arrive parfois que vous rencontriez un bug qui ne se produit que pendant une fraction de seconde, ce qui pose généralement problème pour cerner la source du problème. Pour cela, les développeurs utilisent généralement ce qu'on appelle « les points d'arrêt », aussi nommés « breakpoints » en anglais.

Prenons un autre exemple basé sur des appels de fonctions :

// La fonction « a » affiche la valeur qu'elle reçoit de « b ».
function a(value) {
console.log(value);
}
// La fonction « b » incrémente la valeur reçue par « c » puis la passe en paramètre à « a ».
function b(value) {
a(value + 1);
}
// La fonction « c » incrémente la valeur reçue par la boucle for puis la passe en paramètre à « b ».
function c(value) {
b(value + 1);
}
// Pour chaque itération, cette boucle passe en paramètre la valeur de « i » à la fonction « c ».
for (var i = 0; i < 10; i++) {
c(i);
}

Essayer le code

Pour simplifier, à chaque itération la boucleforappelle la fonctionc(), qui appelle la fonctionb(), qui elle-même appelle la fonctiona(). Cette suite d'appels de fonctions se nomme une « Pile d'exécution », que l'on rencontrera plus fréquemment défini par son terme anglais : « Call Stack ». Grâce aux points d'arrêts nous allons pouvoir étudier la pile d'exécution de notre code. Pour commencer, ouvrez le kit de développement et cliquez sur l'onglet « Sources » pour Chrome et « Débogueur » pour Firefox.

Concernant Chrome, celui-ci vous invitera alors à utiliser le raccourci Ctrl + O (ou Cmd + O sous OS X) afin de choisir un fichier parmi ceux de votre page web, choisissez alors votre fichier JavaScript.

En ce qui concerne Firefox, celui-ci vous présente directement la liste des fichiers de votre page web dans une colonne sur la gauche (nommée « Sources »), sélectionnez votre fichier JavaScript parmi ceux-ci.

Vous devriez maintenant obtenir une des interfaces suivantes (selon votre navigateur) :

Le débogueur de Chrome
Le débogueur de Chrome
Le débogueur de Firefox
Le débogueur de Firefox

Les points d'arrêt

Il est maintenant temps de placer notre premier point d'arrêt. Sur les captures d'écrans précédentes, vous pouvez voir des numéros de ligne à gauche de votre code, cliquez sur le numéro de ligne 3, vous verrez alors apparaître une petite icône montrant que vous avez ajouté un point d'arrêt sur cette ligne.

Un point d'arrêt avec Chome
Un point d'arrêt avec Chome
Un point d'arrêt avec Firefox
Un point d'arrêt avec Firefox

Mais en quoi consiste le point d'arrêt ? Celui-ci permet d'indiquer à votre navigateur que vous souhaitez mettre en pause votre code avant l'exécution de la ligne concernée. Notons que les points d'arrêt ne peuvent être placés que sur des lignes comportant des instructions, il est par exemple impossible d'en placer un sur la déclaration d'une fonction.

Afin que votre point d'arrêt soit pris en compte, il vous faut recharger la page. Une fois que ceci sera fait, votre code sera mis en pause à la ligne concernée et celle-ci sera surlignée en bleu. Vous pourrez alors consulter les variables actuellement utilisées au sein du scope actuel (ici, le scope de la fonctiona()) ainsi que les variables globales.

Sous Chrome, la consultation des variables se fait dans la colonne de droite sous le ruban « Scope Variables ». Les variables du scope courant sont dans le menu « Local » et les variables globales sont dans le menu « Global ».

La consultation des variables avec Chrome
La consultation des variables avec Chrome

Sous Firefox, vous trouverez les variables dans la colonne de droite au sein de l'onglet « Variables ». Les variables du scope courant sont sous le ruban « Portée [...] » (« [...] » désignant généralement le nom de votre fonction) tandis que les variables globales sont sous le ruban « Portée globale ».

La consultation des variables avec Firefox
La consultation des variables avec Firefox

Vous pouvez ainsi voir qu'ici la valeur que notre fonctiona()s'apprête à afficher est2, ce qui est cohérent puisque notre boucle démarre à0, tandis que les fonctionsb()etc()incrémente toutes les deux la valeur.

Cependant, cela ne concerne que la première exécution de notre fonctiona(), qu'en est-il des autres exécutions ? Il suffit pour ça d'indiquer au débogueur que l'exécution du script doit reprendre jusqu'à temps que l'on retombe sur un nouveau point d'arrêt, pour cela vous devez cliquer sur le bouton approprié.

Celui de Chrome se trouve dans la colonne de droite et est représenté par le symbole .

Celui de Firefox se trouve en haut à gauche et est représenté par le symbole .

Une fois la reprise effectuée, votre code sera de nouveau mis en pause au même point d'arrêt car la ligne en question est de nouveau exécutée. La variablevalueaura alors changée, passant de2à3car la boucle en est à sa deuxième itération. Si vous reprenez l'exécution du code, vous verrez alors la valeur augmenter de nouveau et ainsi de suite jusqu'à la fin de l'exécution du script.

La pile d'exécution

Pour chaque point d'arrêt que vous placez dans votre code, vous pouvez consulter la pile d'exécution. Cette dernière définit par quelles fonctions votre code est passé afin d'atteindre la ligne actuellement mise en pause par votre point d'arrêt. Reprenez la page qui nous a servi pour les points d'arrêts, repositionnez un point d'arrêt sur la ligne 3 et rafraîchissez la page. Une fois l'exécution du script mise en pause, vous pouvez observer la pile d'exécution de votre code.

Sous Chrome, vous pouvez la consulter dans la colonne de droite sous le ruban « Call Stack ».

La pile d'exécution sous Chrome
La pile d'exécution sous Chrome

Sous Firefox, la consultation de la pile d'exécution se fait dans la colonne de gauche, sous l'onglet « Pile d'exécution ».

La pile d'exécution sous Firefox
La pile d'exécution sous Firefox

La fonction qui a été exécutée le plus récemment est la première. La dernière représente l'espace global de votre script, avant qu'une première fonction n'ait été exécutée. On voit donc très clairement que notre boucle (qui est exécutée dans l'espace global) a fait appel à la fonctionc(), qui a fait appel àb(), qui a elle-même appeléa().

Un point intéressant concernant cette pile est que vous pouvez cliquer sur chaque étape de la pile et consulter les variables du scope pour chacune de ces étapes. Si vous cliquez sur l'étape « c » vous pourrez alors consulter la valeur de la variablevalueet bien vérifier qu'elle est à0à la première pause du script.

Un autre avantage de cette pile est que parfois vous ne savez pas par quoi a été déclenché une partie de votre code, ceci résout donc ce problème. Cependant, la pile d'exécution n'est pas toujours aussi simple à lire pour deux raisons : sa longueur peut être relativement importante et les fonctions anonymes ne sont pas faciles à identifier, du fait qu'elles soient anonymes !

Une chose importante quand vous créez une fonction anonyme, il est possible de lui donner un nom dans la pile d'exécution afin de mieux vous repérer, essayez le code suivant en mettant un point d'arrêt sur la ligne 3 :

// On utilise ci-dessous une IIFE, on déclare donc une fonction anonyme que l'on exécute immédiatement.
(function anonymousWasHere() {
console.log('Hi!');
})();

Essayer le code

Vous verrez alors apparaître le nom de la fonction dans la pile d'exécution mais celle-ci ne sera accessible nulle part, elle reste donc bien anonyme.

La fonction est anonyme
La fonction est anonyme

Voilà qui clôt ce premier chapitre sur le débogage. De nombreuses autres fonctionnalités sont disponibles dans le panel de débugage de Chrome ou de Firefox, il n'est pas facile de toutes les évoquer en raison de la densité de ce cours mais vous pourrez trouver plus d'informations sur la page de Google pour Chrome ainsi que celle de Mozilla pour Firefox .

En résumé

  • Il existe deux types de bugs : les bugs syntaxiques et les bugs algorithmiques. Le dernier est souvent le plus compliqué à résoudre.

  • Tout navigateur récent et un tant soit peu populaire possède un kit de développement permettant de faciliter le débogage de votre code.

  • La console permet d'afficher les erreurs syntaxiques de votre code mais vous permet aussi d'y afficher du texte ou le contenu d'une variable à l'aide de la méthodeconsole.log().

  • Il est possible d'exécuter du code dans la console et d'accéder aux variables globales de la page actuelle.

  • Les points d'arrêt permettent de mettre en pause votre script à un point précis de votre code et d'analyser l'état du scope courant ainsi que de l'espace global.

  • La pile d'exécution définit par quelles fonctions votre code est passé afin d'atteindre la ligne actuellement mise en pause par un point d'arrêt.