Debugging JavaScript : Techniques Avancées avec DevTools Que Vous Devez Connaître
Salut HaWkers, le debugging est l'une des compétences les plus importantes pour tout développeur, mais beaucoup se limitent encore au console.log(). Les outils de développeur des navigateurs modernes offrent des fonctionnalités puissantes qui peuvent complètement transformer votre façon de trouver et corriger les bugs.
Explorons des techniques avancées qui vont au-delà des bases ?
Au-delà du console.log()
Le console.log() est utile, mais l'objet console offre beaucoup plus :
Console Methods Avancés
// Grouper les logs liés
console.group('Traitement Utilisateur');
console.log('Nom:', user.name);
console.log('Email:', user.email);
console.log('Permissions:', user.permissions);
console.groupEnd();
// Tables pour arrays et objets
const users = [
{ name: 'Ana', age: 28, role: 'Dev' },
{ name: 'Carlos', age: 32, role: 'Lead' },
{ name: 'Maria', age: 25, role: 'Dev' }
];
console.table(users);
// Mesurer le temps d'exécution
console.time('fetchUsers');
await fetchUsers();
console.timeEnd('fetchUsers'); // fetchUsers: 234.5ms
// Comptage d'exécutions
function processItem(item) {
console.count('processItem appelé');
// logique...
}
// Stack trace sans erreur
function deepFunction() {
console.trace('Comment sommes-nous arrivés ici ?');
}
// Assertions pour debugging
console.assert(user.id > 0, 'User ID doit être positif', user);Console Styling
// Logs colorés et stylisés
console.log(
'%c ERREUR %c Échec d\'authentification',
'background: #ff0000; color: white; padding: 2px 6px; border-radius: 3px;',
'color: #ff0000;'
);
console.log(
'%c SUCCESS %c Utilisateur créé',
'background: #00aa00; color: white; padding: 2px 6px; border-radius: 3px;',
'color: #00aa00;'
);
// Styles multiples
console.log(
'%cVariable:%c user.name %c=%c "Jean"',
'color: gray;',
'color: purple;',
'color: gray;',
'color: green;'
);
Breakpoints Conditionnels
Les breakpoints sont plus puissants que de simples pauses dans le code.
Breakpoints avec Condition
Dans Chrome DevTools, cliquez droit sur un breakpoint et sélectionnez "Edit breakpoint" :
// Code original
async function processOrders(orders) {
for (const order of orders) {
await processOrder(order);
}
}
// Condition dans le breakpoint : order.total > 1000
// Ne pause que quand order.total est supérieur à 1000Logpoints (Breakpoints qui ne pausent pas)
Ajoutez des logs sans modifier le code :
// Dans DevTools, ajoutez un logpoint avec :
// "Traitement order:", order.id, "total:", order.total
// Équivalent à ajouter console.log() dans le code,
// mais sans avoir besoin de modifier et rechargerDOM Breakpoints
Pausez quand le DOM change :
- Inspectez l'élément dans le panneau Elements
- Cliquez droit → Break on
- Choisissez : subtree modifications, attribute modifications, ou node removal
// Utile pour trouver le code qui modifie des éléments de façon inattendue
// DevTools va pauser et montrer exactement quel code a fait la modification
Debugging de Code Asynchrone
Le code asynchrone peut être difficile à debugger. Voici des techniques spécifiques :
Async Stack Traces
Chrome DevTools montre le stack trace complet incluant les appels asynchrones :
async function fetchUserData(userId) {
// Breakpoint ici montre tout le chemin asynchrone
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
return data;
}
async function loadDashboard() {
const user = await fetchUserData(currentUserId);
await loadUserPosts(user.id);
await loadUserNotifications(user.id);
}
// Dans le stack trace vous verrez :
// - fetchUserData (async)
// - loadDashboard (async)
// - buttonClickHandler
// - (click event)Promise Rejections
// Activez "Pause on caught exceptions" pour debugger les promises rejetées
async function riskyOperation() {
try {
const result = await mightFail();
return result;
} catch (error) {
// Avec "Pause on caught exceptions" actif,
// le debugger s'arrête ici avant que le catch s'exécute
console.error('Opération échouée:', error);
throw error;
}
}Event Listener Breakpoints
Dans le panneau Sources → Event Listener Breakpoints :
// Cochez des événements spécifiques pour pauser :
// - Mouse → click
// - Keyboard → keydown
// - XHR/Fetch → Any XHR or fetch
// Utile pour comprendre le flux d'événements
// sans avoir besoin d'ajouter des breakpoints manuellement
Performance Profiling
Identifier les goulots d'étranglement de performance est essentiel pour des applications réactives.
Performance Panel
// Démarrez un enregistrement dans le panneau Performance
// Exécutez l'action qui est lente
// Arrêtez l'enregistrement et analysez
// Ce qu'il faut chercher :
// - Long Tasks (tâches > 50ms)
// - Layout Thrashing (beaucoup de reflows)
// - Scripting time élevé
// - Blocking timeIdentifier le Layout Thrashing
// ❌ MAUVAIS - Cause plusieurs reflows
function updateElements(elements) {
elements.forEach(el => {
const height = el.offsetHeight; // Force reflow (lecture)
el.style.height = height + 10 + 'px'; // Force reflow (écriture)
});
}
// ✅ BON - Groupe lectures et écritures
function updateElementsOptimized(elements) {
// D'abord, toutes les lectures
const heights = elements.map(el => el.offsetHeight);
// Ensuite, toutes les écritures
elements.forEach((el, i) => {
el.style.height = heights[i] + 10 + 'px';
});
}Memory Profiling
// Dans le panneau Memory, prenez des snapshots pour identifier les memory leaks
// Pattern courant de memory leak :
class Component {
constructor() {
// Event listener qui n'est jamais supprimé
window.addEventListener('resize', this.handleResize);
}
handleResize = () => {
// ...
};
// ❌ Sans cleanup, le listener maintient une référence au composant
}
// ✅ Correction :
class ComponentFixed {
constructor() {
window.addEventListener('resize', this.handleResize);
}
handleResize = () => {
// ...
};
destroy() {
window.removeEventListener('resize', this.handleResize);
}
}
Source Maps et Debugging de Code Minifié
Configuration des Source Maps
// webpack.config.js
module.exports = {
devtool: 'source-map', // Production
// ou
devtool: 'eval-source-map', // Développement (plus rapide)
};
// vite.config.js
export default {
build: {
sourcemap: true,
},
};Debugging avec Source Maps
Avec les source maps configurés, vous pouvez :
- Voir le code original dans le panneau Sources
- Ajouter des breakpoints dans le code TypeScript/ES6+
- Voir les variables avec leurs noms originaux
- Les stack traces pointent vers les fichiers originaux
// Code TypeScript original
interface User {
id: number;
name: string;
}
async function getUser(id: number): Promise<User> {
// Breakpoint ici fonctionne normalement
const response = await fetch(`/api/users/${id}`);
return response.json();
}
Snippets et Overrides
Snippets Réutilisables
Créez des snippets dans DevTools pour des tâches répétitives :
// Snippet : Vider localStorage et recharger
(function clearAndReload() {
localStorage.clear();
sessionStorage.clear();
location.reload();
})();
// Snippet : Exporter les données de la console
(function exportConsoleData() {
const data = /* vos données */;
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'export.json';
a.click();
})();
// Snippet : Surveiller tous les appels fetch
(function monitorFetch() {
const originalFetch = window.fetch;
window.fetch = async (...args) => {
console.group('Fetch Request');
console.log('URL:', args[0]);
console.log('Options:', args[1]);
const start = performance.now();
const response = await originalFetch(...args);
const duration = performance.now() - start;
console.log('Status:', response.status);
console.log('Duration:', duration.toFixed(2) + 'ms');
console.groupEnd();
return response;
};
console.log('Surveillance fetch activée');
})();Local Overrides
Modifiez des fichiers de production localement :
- Dans le panneau Sources, créez un dossier overrides
- Sélectionnez un fichier et éditez
- Les changements persistent entre les rechargements
- Utile pour tester des fixes en production sans deploy
Network Debugging
Filtres Avancés
// Dans le panneau Network, utilisez des filtres :
// Par type
// is:running - Requêtes en cours
// larger-than:1M - Plus grandes que 1MB
// status-code:500 - Seulement status 500
// Par domaine
// domain:api.example.com
// Expressions négatives
// -domain:analytics.com - Exclure domaine
// Filtres multiples
// method:POST status-code:400Throttling et Offline
// Simuler des connexions lentes
// Network panel → No throttling → Sélectionnez :
// - Slow 3G
// - Fast 3G
// - Offline
// Ou créez des profils personnalisés :
// - Download: 100kb/s
// - Upload: 50kb/s
// - Latency: 500msConclusion
Maîtriser les outils de debugging transforme votre productivité en tant que développeur. Au lieu de deviner où est le problème, vous pouvez aller directement à la cause racine.
Quelques bonnes pratiques recommandées :
- Utilisez des breakpoints conditionnels au lieu de multiples
console.log() - Apprenez les raccourcis clavier de DevTools
- Utilisez les logpoints quand vous ne voulez pas modifier le code
- Faites du profiling régulièrement pour identifier les problèmes de performance avant qu'ils ne deviennent critiques
Les outils sont disponibles gratuitement dans tous les navigateurs modernes. Ça vaut la peine d'investir du temps pour les maîtriser.
Si vous voulez continuer à approfondir vos connaissances en JavaScript, je recommande de consulter l'article Web APIs Modernes du Navigateur avec JavaScript en 2025 où nous explorons des APIs puissantes qui peuvent améliorer vos applications.

