Debugging Javascript — Part 1: Sources

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 .


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:

x = calculateX(input);
if (something) {
} else {

with the console output looking like that:


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.


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

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

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

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

Variable Inspection

Variable Inspection through hovering — Screenshot from

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

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

Call stack Inspection

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

Navigation options

Breakpoint resume options — Screenshot from

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.
  2. Another option would be to simply resume execution “line by line”. This is useful in situations where you are “paused” on a line of code containing a function that’s not relevant to the problem you’re debugging and you want to execute the function without stepping into it. By clicking on this option (marked with a blue circle in the screenshot above) you will resume the execution for whatever happens on the line and then the thread will “pause” again. In the code above, the thread (which is currently paused on A) will pause on D when this button is clicked.
  3. If the line does contain relevant code though, then you can step into it, by clicking on the button with the “arrow-down” icon (marked with a green circle in the screenshot above). This is useful in scenarios where further investigation is needed on how an output got calculated. In the example above, the thread (which is currently paused on A) will pause on B, C and D supposing you keep clicking the button.
  4. In cases where a particular function you’ re inspecting is too big, you can step out of it and pause again. This is useful in scenarios where you have already stepped into a function (with the previous navigation option) and you’ re like “ok, i’m done with that”. To understand that, suppose you are paused on A, then you click the navigation option № 3. This would pause the thread on B. If getName was too big of a function you could click “step out” and instead of going to C, you would instantly go to D.
  5. If you got sick of all these navigation options, then good news! You can press on the “Deactivate breakpoints” switch (marked with a purple circle in the screenshot above) and you will disable all breakpoints until you press on it again. No matter how many more breakpoints you add, nothing will happen as long as this switch is active. This is very helpful in scenarios where you have a lot of breakpoints in different files and you don’t want to erase them, but simply de-activate them for a while, because you have been overran by “pauses” and no matter how many times you keep pressing the “play” button, there always is another breakpoint that “pauses” the app.
    This is the perfect place to mention that all of your breakpoints will always be visible in the Breakpoints Section on the right sidebar. From there, you can enable, disable or remove them in a more fine-grained fashion. Just right-click on one of them and you’ll see all the available options.
  6. Lastly, the most interesting switch of them all is the “pause on exceptions” button. This will add a breakpoint automatically whenever a Javascript exception occurs. This is helpful in scenarios where your code throws an exception, but you’ re not fully aware of what’s causing it. Having this switch active (marked with an orange circle in the screenshot above) can help you out identify the problematic piece of code.
    These automatic breakpoints are in fact an interesting feature of the dev tools. You can tell the system to automatically add breakpoints whenever a request to a particular URL is sent (check out XHR/Fetch Breakpoints Section) or whenever a particular event occurs like clicks & hovers (check out Event Listener Breakpoints). The latter can be extremely helpful when debugging your logging mechanisms, but because this article series aims to familiarise people with debugging, we won’t be focusing on these advanced uses. Just thought we should mention them, so you know that these features exist.

Closing Notes

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 😀

Front-end ReactJS Developer —