Swizec Teller - a geek with a hatswizec.com

Senior Mindset Book

Get promoted, earn a bigger salary, work for top companies

Senior Engineer Mindset cover
Learn more

    Javascript debugging [slightly] beyond console.log

    debugger;
    debugger;

    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.

    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 setTimeouts 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.

    The debugger, initial view
    The debugger, initial view

    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.

    Console is in current scope
    Console is in current scope

    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.

    Published on January 14th, 2015 in Frontend Web, JavaScript, Technical

    Did you enjoy this article?

    Continue reading about Javascript debugging [slightly] beyond console.log

    Semantically similar articles hand-picked by GPT-4

    Senior Mindset Book

    Get promoted, earn a bigger salary, work for top companies

    Learn more

    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 ❤️

    Created by Swizec with ❤️