My favourite tool for javascript debugging is console.log
.
I mean, I love console.log
. If I ever get a programming tattoo, it's going to be console.log
or some variation thereof. Simple to use, works every time, and every programming language I've used since I was 9 has had some variation of it.
console.log forever
— Swizec Teller (@Swizec) July 21, 2021
been coding for 20 years and it's still the best https://t.co/AMCHGWU1YT
Pascal acting up? Not sure what's going on? writeln
Python being silly? print
C acting funny? printf
CSS weird? border: 1px solid red
HTML messing with you? Nah, Chrome's element inspector.
But as much as I love console.log
, sometimes it just does not do. Sure, if you have a proper test suite console.log
is always enough. But you don't always have a proper test suite.
Let me explain.
When you want to understand what's going on and where exactly a piece of code goes wrong, you do something like this.
var do_something = function (arg1) {
console.log("got into function", arg1);
var foo = get_my_foo(arg1);
do_another_thing();
console.log("foo changed?", foo);
return foo;
};
Not the prettiest. But it works. You can tell what's going on.
You know for certain the function was called, what the argument value was, and you know the value of foo
when it returns.
Perfect for calling the code once. But what if it's part of a list building mechanism?
a_lot_of_things.map(function (thing) {
var label = do_something(thing);
$("ul").append($("<li></li>").html(label));
});
Wellp, now you've got a bunch of console output to look through. Annoying, but manageable. You can still tell which argument produces which output.
But we're stretching the limits of console.log
here.
Now what if somebody does this?
async.map(a_lot_of_things, function (thing) {
var label = do_something(thing);
$("ul").append($("<li></li>").html(label));
});
Wow, that's annoying. Your do_something
function is called asynchronously. The output is all jumbled up!
Very annoying. But you can map input to output in your mind. They're both printed right next to each other.
It's just harder because you have to read the whole output every time and can't jump to the line you're interested in. The problem is ALWAYS with just one of the elements. Obviously.
Wow, we're really stretching that console.log
. Let's break it.
var do_something = function (arg1, callback) {
console.log("got into function", arg1);
var foo = get_my_foo(arg1);
setTimeout(function () {
do_another_thing();
console.log("foo changed?", foo);
callback(foo);
}, 100);
};
async.map(a_lot_of_things, function (thing) {
do_something(thing, function (label) {
$("ul").append($("<li></li>").html(label));
});
});
You wouldn't just spray setTimeout
s in your code like that. But now you have an asynchronous function. Maybe it's an Angular watch, you're responding to a promise, or something.
Point is, all of your console.log
outputs are now jumbled up and useless. Something like this:
got into function, foo1 got into function, foo3 foo changed?, yes got into
function, foo2 foo changed?, no got into function, foo4 got into function, foo5
foo changed?, yes foo changed?, no foo changed?, yes
Wow, talk about useless!
When faced with a situation like this, I would start adding alert()
s to my code. It stops execution and lets you look at the output in a particular moment.
But it blocks the entire browser, you can't look around much, and clicking all those pop ups is annoying as hell. Especially once you've found the culprit, but can't just refresh the page.
alert()
disables Cmd+R because it steals focus from the window. You have to get to the end of the loop before you can stop it.
:(
A few weeks ago I stumbled onto a better way through someone's throwaway comment. debugger;
It. Is. Magic.
Instead of that second print statement, console.log("foo changed?", foo)
, we'd put debugger;
. When Chrome, and other modern browsers?, sees that statement, it stops.
But it doesn't just stop. It gives you a debugger.
You can't see it in the screenshot, but even GIFs are stopped. A moment ago that Santa was dancing, now everything is in "Holy shit, he's debugging!" mode.
The code that triggered debugger;
is in the middle. A bunch of inspection tools are on the right. On top of the screen is an "I'm done now, please continue" button.
But more importantly, the console is in current scope! You can do whatever you want.
And once you've found the culprit, you can just refresh the page. No waiting for all the alert()
s to show up.
Now, I'm not going to stop using console.log
any time soon. But knowing about debugger
has made my life easier many times.
I only wish I'd known about it sooner.
Continue reading about Javascript debugging [slightly] beyond console.log
Semantically similar articles hand-picked by GPT-4
- Chrome's console.log is the slowest
- Waiting for Godot with callbacks, promises, and async
- Cool thing Thursday: alertify.js
- I added linting to a 3-year old project. You can totally guess what happened next.
- A cool JavaScript property you never noticed
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️