Debugging Javascript — Part 1: Sources

Aggelos Arvanitakis
Aug 21, 2018 · 10 min read

This is Part 1 of a series that will explore debugging of a front-end Javascript application. Debugging can be reduced down to proper knowledge of the developer tools that each browser offers. In this article we will be focusing on Chrome developer tools and in particular how you can get the most out of the Sources tab, by focusing only on the most commonly used tools .


Intro

So you ’re reading the job requirements for a front-end position you ‘re going to apply for. Suddenly you stumble upon a bullet point saying “Exceptional debugging skills” and you think to yourself “yeah, i got this… don’t Ι?”

There are actually a lot of misconceptions about what debugging skills actually are. It’s often considered the art of finding out what’s wrong, regardless of the time it takes. You may even believe that it’s tied to the intelligence of a person, in the form of being able to stare at a bunch of lines and figure out what’s going wrong with the code. If this fails, then you give up and the console.log and alert() commands take place. Every blank line becomes a candidate for a console.log in order to see the how the code executes. Most of the times it’s like that:

...
...
console.log(input)
x = calculateX(input);
console.log(x);
if (something) {
console.log('inside');
} else {
console.log('outside');
}
...
...

with the console output looking like that:

1.232
23232
outside

Seeing that, you might go “erm ok that’s expected. The problem must be somewhere else” and you begin to do the exact same thing at another part of your code, while simultaneously needing to rebuild your bundle (or refresh your page) for these changes to apply.

Finally, you figure out the issue and write a fix for that. You’ re like “perfect let’s push that ASAP so that the app stops crashing on production”. After having deployed, you suddenly see that you forgot to erase some of the debugging commands that you have added. If it’s a console.log then that’s tolerable, but if it’s an alert then you might have a problem. So you go and push another commit named “removed console.logs” or “removed unnecessary alert” to take care of that, while polluting your commit history.


Breakpoints

They are here to give you access to a set of tools that will replace any console.log or alert command you might have used in the past. These essentially “pause” the execution of the main Javascript thread powering your application, while allowing you to see a snapshot of the state that your application is in. Best thing is that no refresh or re-bundle is needed, so you can simply keep adding or removing breakpoints dynamically on runtime.

To add a breakpoint, you first need to open your developers tools (CMD+Shift+I on Mac and CTRL+Shift+I on Windows) and navigate to the Sources tab. This tab contains all of your application files and what you see is what Chrome “sees”. If a file there seems different than what you have in your Editor or IDE, then Chrome hasn’t yet received your code updates (probably due to caching). You can also manipulate your files directly in the Sources tab (should you wish to) and Chrome will be directly notified of your updates.

Screenshot of a file from google.com

By pressing CMD+P (or CTRL+P on windows) you have access to a nice search bar that allows you to open the file that you are interested in debugging, similar to the way you’ d do it in your local IDE. Chrome orders the lines of the code in every file and by clicking on a line number you can add a breakpoint to this particular line (re-clicking it removes it). Whenever the main Javascript thread attempts to execute a “breakpointed” line of code, it will pause and wait.

Active breakpoint on line 13 — Screenshot from google.com

If you only want to pause the thread under certain conditions, Chrome has an awesome feature that allows you to do that. This is useful in scenarios where your code will be passing through the “breakpointed” line a lot, but you only want it to “pause” on one occurrence of it. After you add a breakpoint you can “right-click” on it, select the option Edit Breakpoint and then type in an expression. The thread will now “pause” only when your expression evaluates to true and ignore the presence of the breakpoint whenever this expression is false. In the expression, you can make use of all variables that Chrome has calculated up to this point.

Conditional Breakpoint — Screenshot from google.com

Let’s talk now of what you can do when the execution of your app has paused.


Variable Inspection

First things first, you can hover on every computed variable (variables that are above the “breakpointed” line) and see their current values. By pressing ESC, you can also toggle the console window which will allow you to run custom code using any of the computed variables; something extremely useful for custom checks and comparisons.

Variable Inspection through hovering — Screenshot from google.com

Variables that have been calculated in the same closure or not declared in this file at all but still utilised by it, can be found in the Scopes Section. This section is located in the right sidebar and it contains all the entities used by this file, grouped by the scope they belong to (local, global, closure etc.) with relation to the “pausing” breakpoint. For example, if the breakpoint is within a function, then everything that is declared inside this function is considered “local” and everything declared in another function that’s wrapping our current function is considered “closure” and so on. Take a look in this section and you will see everything that Chrome has calculated up to this point.

Scopes section — Screenshot from google.com

Should you wish to track the value changes of a handful of variables throughout the app’s execution, then the Watch Section might interest you. This is another nifty feature that replaces the need for a constant console.log in order to get the latest value of some variable(s). By clicking on the “plus” icon (marked with a green circle in the screenshot below), an autocomplete searchbar will open, where you can type the name of the variable that you want to watch (regardless of the file that it exists in). Doing so, allows you to monitor its value throughout the your app’s execution. You could consider Watch Section as an extension to the Scopes Section, since it allows you to select the variables that you want to continuously monitor, instead of simply inspecting the values of the entities that this particular file (the one with the breakpoint) needed.
Important: The Watch Section doesn’t provide a live update, unless you inspect it between “pauses” (navigate between breakpoints). Thus, if the values of your watched variables might have changed without a pause occurring, then you will need to hit the “refresh” button (marked with a blue circle in the screenshot below) in order to get their latest value.

Watch Section — Screenshot from google.com

Call stack Inspection

You now have a way of knowing the value of every variable when your application is “paused”, but we haven’t answered the question of “how the hell did it get to this line?”. The Call Stack section of the sources tab, will give you everything you need to know about that. This contains a stack of the function calls and invocations that lead to the thread reaching the “breakpointed” line. Imagine it like a trail of events that lead to the current state. The lower you go in the stack the older the commands. Each stack entry “explains” why your code jumped to the stack entry right above it. This means that the code marked by the second-to-top stack entry was the reason the thread was forced to execute the code marked by the top entry.

To inspect this code, you click on an entry in the stack and it will automatically open the file and highlight the particular line. While there, you can also inspect the variables of each entry in the stack, at the very moment that the related code was invoked, as if you had an invisible debugger active on this line! Simply, click on a call stack entry and then either hover over a variable or check out the the entry’s Scopes Section.

Call Stack Section — Screenshot from google.com

Navigation options

Now that we went through what you can do while paused, let’s see what options you have in order to continue with the execution.

Breakpoint resume options — Screenshot from google.com

To fully understand the navigation options we will be using the following simple code that is currently “paused” through a breakpoint on line A.

function updateHeader() {
const name = getName(); // A
const x = 1; // D
}
function getName() {
const name = `${app.first} ${app.last}`; // B
return name; // C
}
  1. The most common option would be to simply click on the “play” icon and everything will continue as normal until another breakpoint is encountered. This option is marked with a red circle in the screenshot above. In our example, supposing that no other breakpoint exists on lines B, C and D, then the code will never pause again.

Closing Notes

If you are a new front end developer, there is a high chance you might feel uncomfortable using some of the tools presented above, but if you spend some time familiarising yourself with them, you will see a lot of difference in the speed and easiness that you debug code.

In the next article we will be focusing on DOM inspection & manipulation, as well as DOM breakpoints.

Thanks for your time :)

P.S. 👋 Hi, I’m Aggelos! If you liked this, consider following me on twitter and sharing the story with your developer friends 😀

Thanks to Konstantinos Siaterlis

Aggelos Arvanitakis

Written by

Front-end ReactJS Developer — https://aggelos.dev

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade