JavaScript Debugging With DevTools
Debugging means finding and fixing mistakes (bugs) in your code. Every browser has free tools for this, called DevTools.
Opening DevTools
| Browser | Shortcut |
|---|---|
| Chrome, Edge | F12 or Ctrl + Shift + I (Cmd + Option + I on Mac) |
| Firefox | F12 or Ctrl + Shift + I |
| Any browser | Right-click on the page and choose Inspect |
The tabs you will use most:
| Tab | Use it to |
|---|---|
| Console | See errors and messages, and run JavaScript |
| Elements (Inspector) | See and edit the live HTML and CSS |
| Sources (Debugger) | Pause code with breakpoints and step through it |
| Network | See every file and request the page loads |
| Application (Storage) | See localStorage, sessionStorage and cookies |
Reading an Error Message
When code breaks, the Console shows a red message like this:
Uncaught TypeError: Cannot read properties of undefined (reading 'price')
at getTotal (shop.js:14:22)
at HTMLButtonElement.<anonymous> (shop.js:30:5)Read it in three parts:
- The type:
TypeError, a value was not what the code expected - The message: something was
undefinedwhen you tried to readpricefrom it - The location: file
shop.js, line 14, column 22, insidegetTotal. Click it to jump to that line
The lines below are the stack trace: the chain of calls that led to the error.
More Than console.log
The console object has many useful methods:
Example
<!DOCTYPE html>
<html>
<body>
<p>Open DevTools (F12), go to the Console tab, then press Run again.</p>
<p id="demo"></p>
<script>
const students = [
{ name: "Ali", marks: 78 },
{ name: "Sana", marks: 92 },
{ name: "Hamza", marks: 45 }
];
console.log("Plain message");
console.info("Info: loaded", students.length, "students");
console.warn("Warning: Hamza is close to failing");
console.error("Error: example error message");
console.table(students);
console.group("Results");
students.forEach(s => console.log(s.name, s.marks >= 50 ? "pass" : "fail"));
console.groupEnd();
console.time("loop");
let sum = 0;
for (let i = 0; i < 1_000_000; i++) sum += i;
console.timeEnd("loop");
console.assert(sum > 0, "Sum should be positive");
document.getElementById("demo").textContent = "Done! Check the Console.";
</script>
</body>
</html>Try it Yourself »| Method | Shows |
|---|---|
console.log() | A normal message |
console.warn() / console.error() | Yellow warning / red error |
console.table(array) | An array of objects as a table |
console.group() / groupEnd() | Folds messages into a group |
console.time(label) / timeEnd(label) | How long code took |
console.assert(condition, msg) | Shows msg only if the condition is false |
console.count(label) | How many times this line ran |
Tip: write console.log({ total, discount }) with curly brackets. The Console then shows the variable names next to their values.
Breakpoints
console.log is fine for small things, but a breakpoint is more powerful. It pauses the code on a line, so you can look at every variable at that moment.
- Open the Sources tab and find your file
- Click the line number. A blue marker appears
- Do the action that runs that code (for example, click the button)
- The page freezes on that line. Hover over variables to see their values, or look in the Scope panel
The debugger Statement
You can also put a breakpoint in the code itself with debugger;. When DevTools is open, the code pauses there. When DevTools is closed, it does nothing.
Example
<!DOCTYPE html>
<html>
<body>
<p>Open DevTools first, then click the button.</p>
<button id="btn">Calculate bill</button>
<p id="demo"></p>
<script>
function calculateBill(items) {
let total = 0;
for (const item of items) {
debugger; // pauses here on every loop round
total += item.price * item.qty;
}
return total;
}
document.getElementById("btn").addEventListener("click", () => {
const items = [
{ name: "Naan", price: 30, qty: 4 },
{ name: "Karahi", price: 1800, qty: 1 }
];
document.getElementById("demo").textContent = "Total: Rs " + calculateBill(items);
});
</script>
</body>
</html>Try it Yourself »Total: Rs 1920
Remember to remove debugger lines before you publish your site.
Stepping Through Code
While paused, use the buttons at the top of the debugger panel:
| Button | Shortcut | What it does |
|---|---|---|
| Resume | F8 | Run until the next breakpoint |
| Step over | F10 | Run this line, then pause on the next one |
| Step into | F11 | Go inside the function called on this line |
| Step out | Shift + F11 | Finish this function and pause after it |
The Watch panel lets you type an expression, like item.price * item.qty, and see its value change as you step.
Other Useful Breakpoints
- Conditional breakpoint: right-click a line number and add a condition like
item.qty > 10. It only pauses when the condition is true. - Logpoint: right-click and add a message. It logs without changing your code.
- Event listener breakpoints: in Sources, pause whenever any
clickorkeydownhappens. - Pause on exceptions: pause exactly where an error is thrown.
Checking Requests in the Network Tab
If fetch does not work, open Network and run it again. Click the request to see:
- The status (200 is OK, 404 is not found, 500 is a server error)
- The Headers you sent and received
- The Response the server sent back
A Simple Debugging Routine
- Read the error message and go to the line it names
- Make the bug happen again, the same way, every time
- Pause before the line and check the values
- Find the first value that is wrong, then ask why
- Fix it, and test again with good and bad input
Exercise
Exercise
What does the debugger; statement do when DevTools is open?
