If you've ever struggled with how to debug javascript like a pro, you're not alone. In this hands-on tutorial, I'll walk you through everything from the basics to real-world applications — with code you can actually use in your projects.
Table of Contents
Console Methods Beyond console.log
Most developers only use console.log(), but the Console API has much more powerful tools:
// Structured data display
const users = [
{ name: 'Alice', age: 28, role: 'developer' },
{ name: 'Bob', age: 32, role: 'designer' },
{ name: 'Charlie', age: 25, role: 'developer' },
];
console.table(users); // Beautiful table format!
// Group related logs
console.group('User Authentication');
console.log('Checking token...');
console.log('Token valid');
console.log('Loading user data...');
console.groupEnd();
// Timing operations
console.time('fetchData');
await fetch('/api/data');
console.timeEnd('fetchData'); // "fetchData: 142.5ms"
// Conditional logging
console.assert(users.length > 0, 'No users found!'); // Only logs if false
// Count occurrences
for (const user of users) {
console.count(user.role); // "developer: 1", "designer: 1", "developer: 2"
}
// Styled console output
console.log(
'%c DRIXO Debug %c v1.0',
'background: #00d4aa; color: #1a1a2e; padding: 4px 8px; font-weight: bold;',
'background: #1a1a2e; color: #00d4aa; padding: 4px 8px;'
);
Breakpoints and the Debugger Statement
// Add breakpoints directly in code
function processOrder(order) {
const total = order.items.reduce((sum, item) => sum + item.price, 0);
debugger; // Execution pauses here when DevTools is open
if (total > 1000) {
applyDiscount(order, 0.1);
}
return total;
}
// Conditional breakpoints (set in DevTools):
// Right-click a line number → "Add conditional breakpoint"
// Example: order.total > 500
// The breakpoint only triggers when the condition is true
Types of breakpoints in Chrome DevTools:
- Line breakpoints — Click line number in Sources panel
- Conditional breakpoints — Right-click line → Add conditional breakpoint
- DOM breakpoints — Right-click element → Break on → subtree modifications
- XHR/Fetch breakpoints — Sources → XHR/fetch Breakpoints → Add URL pattern
- Event listener breakpoints — Sources → Event Listener Breakpoints → click, keyboard, etc.
Network Debugging
// Intercept and log all fetch requests
const originalFetch = window.fetch;
window.fetch = async function(...args) {
const url = args[0];
console.log(`🌐 Fetch: ${typeof url === 'string' ? url : url.url}`);
console.time(`fetch-${url}`);
try {
const response = await originalFetch.apply(this, args);
console.timeEnd(`fetch-${url}`);
console.log(` Status: ${response.status} ${response.statusText}`);
// Clone response to read body without consuming it
const clone = response.clone();
clone.json().then(data => {
console.log(' Response:', data);
}).catch(() => {});
return response;
} catch (error) {
console.timeEnd(`fetch-${url}`);
console.error(` Error: ${error.message}`);
throw error;
}
};
Error Tracking Patterns
// Global error handler
window.addEventListener('error', (event) => {
console.error('Uncaught error:', {
message: event.message,
file: event.filename,
line: event.lineno,
column: event.colno,
stack: event.error?.stack
});
// Send to error tracking service
// reportError(event.error);
});
// Promise rejection handler
window.addEventListener('unhandledrejection', (event) => {
console.error('Unhandled promise rejection:', event.reason);
event.preventDefault(); // Prevent default console error
});
// Custom error classes for better debugging
class ValidationError extends Error {
constructor(field, message) {
super(`Validation failed for "${field}": ${message}`);
this.name = 'ValidationError';
this.field = field;
}
}
class APIError extends Error {
constructor(endpoint, status, body) {
super(`API Error ${status} at ${endpoint}`);
this.name = 'APIError';
this.status = status;
this.endpoint = endpoint;
this.body = body;
}
}
// Usage
try {
throw new ValidationError('email', 'Invalid format');
} catch (e) {
if (e instanceof ValidationError) {
console.log(`Fix field: ${e.field}`);
}
}
Performance Debugging
// Performance API for precise measurements
performance.mark('start-render');
// ... rendering logic ...
performance.mark('end-render');
performance.measure('render-time', 'start-render', 'end-render');
const measure = performance.getEntriesByName('render-time')[0];
console.log(`Render took: ${measure.duration.toFixed(2)}ms`);
// Memory debugging (Chrome only)
if (performance.memory) {
console.log({
totalJSHeap: (performance.memory.totalJSHeapSize / 1048576).toFixed(2) + ' MB',
usedJSHeap: (performance.memory.usedJSHeapSize / 1048576).toFixed(2) + ' MB',
heapLimit: (performance.memory.jsHeapSizeLimit / 1048576).toFixed(2) + ' MB'
});
}
// Find slow functions with a simple profiler
function profileFunction(fn, label) {
return function(...args) {
const start = performance.now();
const result = fn.apply(this, args);
const duration = performance.now() - start;
if (duration > 16) { // Longer than one frame (60fps)
console.warn(`⚠️ ${label} took ${duration.toFixed(2)}ms (janky!)`);
}
return result;
};
}
// Wrap any function to monitor its performance
const renderList = profileFunction(function(items) {
// expensive rendering logic
}, 'renderList');
Debugging Checklist
When you hit a bug, follow this systematic approach:
- Reproduce consistently — Find the exact steps to trigger the bug
- Read the error message — Sounds obvious, but read every word
- Check the stack trace — Work backwards from the error
- Isolate the problem — Comment out code until the error stops
- Check your assumptions — console.log the values you think you know
- Search the error message — Stack Overflow has seen your bug before
- Take a break — Fresh eyes catch bugs faster than tired ones
Pro Tip: Use
console.trace() to see the full call stack at any point in your code — it's incredibly useful for tracing where a function was called from.AM
Arjun Mehta
Full-Stack Developer & Technical Writer at DRIXO
Full-Stack Developer & Technical Writer at DRIXO
Full-stack developer with 5+ years of experience in Python and JavaScript. I love breaking down complex concepts into simple, practical tutorials. When I'm not coding, you'll find me contributing to open-source projects.
Comments