Signup to the waiting list!
Debugging is one of those skills that’s core to the activity of a programmer.
Sometimes we do our best work, yet the program is not working correctly, for example it’s crashing, it’s just slow or it’s printing wrong information.
What do you do when a program you wrote is not behaving like you expect?
You start debugging it.
Figuring out where the error could be
The first step is always to look at what is happening, and trying to determine where is the problem coming from. Is it a problem in the environment? Is it a problem in the input you gave to the program? Is it a one-time crash due to too much memory usage? Or is it happening every time you run it?
Those are all key information to start going in the right direction when figuring out a problem.
Once you have some sort of idea where the error is coming from, you can start checking that specific part of code.
Read the code
The simplest way to debug, at least in terms of tooling, is by reading the code you wrote. Aloud. There is some magical thing in hearing from our own voice that does not happen when you read in silence.
Often times I found problems in this way.
Using the console
If reading the code reveals nothing to you, the next logical step is to start adding a few lines into your code that can shed some light.
console.log (and its cool friends).
Consider this line:
const a = calculateA() const b = calculateB() const result = a + b
Somehow the result is not correctly calculated, so you can start by adding
alert(b) before calculating the result, and the browser will open two alert panels when it executes the code.
const a = calculateA() const b = calculateB() alert(a) alert(b) const result = a + b
This works fine if what you are passing to
alert() is a string or a number. As soon as you have an array or an object things start to be too complicated for
alert(), and you can use the Console API. Starting with
const a = calculateA() const b = calculateB() console.log(a) console.log(b) const result = a + b
The Chrome Dev Tools
The result of the
The tool is very powerful and lets you print complex objects or arrays and you can inspect every property of them.
In the Console API post you can see all the options and details of working with it, so I’m not explaining all the details here.
The debugger is the most powerful tool in the browser developer tools, and it’s found in the Sources panel:
The top part of the screen shows the files navigator.
You can select any file and inspect it on the right. This is very important to set breakpoints, as we’ll see later.
The bottom part is the actual debugger.
At this point the execution is halted and you can inspect all about your running program.
You can check the variables values, and resume the execution of the program one line at a time.
But first, what is a breakpoint? In its simple form, a breakpoint is a
breakpoint instruction put in your code. When the browser meets it, it stops.
This is a good option while developing. Another option is to open the file in the Sources panel and click the number on the line you want to add a breakpoint:
Clicking again the breakpoint will remove it.
After you add a breakpoint you can reload the page and the code will stop at that execution point when it finds the breakpoint.
As you add the breakpoint you can see in the Breakpoints panel that
form.js on line
7 has the breakpoint. You can see all your breakpoints there, and disable them temporarily.
There are other types of breakpoints as well:
- XHR/fetch breakpoints: triggered when any network request is sent
- DOM breakpoints: triggered when a DOM element changes
- Event listener breakpoints: triggered when some event happens, like a mouse click
In this example I set a breakpoint inside an event listener, so I had to submit a form to trigger the it:
Now all the variables that are in the scope are printed, with their respective values. You can edit those variables by double clicking them.
Watch variables and expressions
Right to the Scope panel there’s the Watch panel.
It has a
+ button which you can use to add any expression. For example adding
name will print the
name variable value, in the example
Flavio. You can add
name.toUpperCase() and it will print
Resume the execution
Now the scripts are all halted since the breakpoint stopped the execution.
There is a set of buttons above the “Paused on breakpoint” banner that let you alter this state.
The first is in blue. Clicking it resumes the normal script execution.
The second button is step over, and it resumes execution until the next line, and stops again.
The next button perform a step into operation: goes into the function being executed, letting you go into the details of it.
Step out is the opposite: goes back to the outer function calling this one.
Those are the main ways to control the flow during debugging.
From this devtools screen you can edit any script, also while the script is halted in its execution. Just edit the file and press cmd-S on Mac or ctrl-S on Windows/Linux.
Of course the changes are not persisted to disk unless you are working locally and set up workspaces in the devtools, a more advanced topic.
Inspect the call stack
Often times you work with libraries where you don’t want to “step into”, you trust them and you don’t want to see their code in the call stack, for example. Like in the above case for
validator.min.js, which I use for email validation.
I trust it does a good job, so I can right-click it in the call stack and press Blackbox script. From then on, it’s impossible to step into this script code, and you happily work on just your own application code.
Use the browser devtools to debug Node.js
Since Node.js is built on the same engine of Chrome, v8, you can link the 2 and use the Chrome DevTools to inspect the execution of Node.js applications.
Open your terminal and run
Then in Chrome type this URL:
Click the Open dedicated DevTools for Node link next to the Node target, and you’ll have access to Node.js in the browser DevTools:
Make sure you click that, and not the inspect link down below, as it tool auto-reconnects to the Node.js instance when we restart it - pretty handy!
More js tutorials:
- The Complete ECMAScript 2015-2019 Guide
- A list of sample Web App Ideas
- Introduction to Unicode and UTF-8
- Introduction to ES Modules
- Introduction to CommonJS
- A Moment.js tutorial
- The ES6 Guide
- The ES2016 Guide
- The ES2017 Guide
- The ES2018 Guide
- How to use Async and Await with Array.prototype.map()
- Async vs sync code
- HTML Canvas API Tutorial
- What is a Single Page Application?
- An introduction to WebAssembly
- Introduction to JSON
- The JSONP Guide
- Should you use or learn jQuery in 2020?
- Introduction to PeerJS, the WebRTC library
- Work with objects and arrays using Rest and Spread
- The TypeScript Guide
- Loosely typed vs strongly typed languages
- The node_modules folder size is not a problem. It's a privilege
- The String replace() method
- The String search() method
- The ES2019 Guide
- The String charAt() method
- The String charCodeAt() method
- The String codePointAt() method
- The String concat() method
- The String endsWith() method
- The String includes() method
- The String indexOf() method
- The String lastIndexOf() method
- The String localeCompare() method
- The String match() method
- The String normalize() method
- The String padEnd() method
- The String padStart() method
- The String repeat() method
- The String slice() method
- The String split() method
- The String startsWith() method
- The String substring() method
- The String toLocaleLowerCase() method
- The String toLocaleUpperCase() method
- The String toLowerCase() method
- The String toString() method
- The String toUpperCase() method
- The String trim() method
- The String trimEnd() method
- The String trimStart() method
- The String valueOf() method
- The Number isInteger() method
- The Number isNaN() method
- The Number isSafeInteger() method
- The Number parseFloat() method
- The Number parseInt() method
- The Number toString() method
- The Number valueOf() method
- The Number toPrecision() method
- The Number toExponential() method
- The Number toLocaleString() method
- The Number toFixed() method
- The Number isFinite() method
- The Object assign() method
- The Object create() method
- The Object defineProperties() method
- The Object defineProperty() method
- The Object entries() method
- The Object freeze() method
- The Object getOwnPropertyDescriptor() method
- The Object getOwnPropertyDescriptors() method
- The Object getOwnPropertyNames() method
- The Object getOwnPropertySymbols() method
- The Object getPrototypeOf() method
- The Object is() method
- The Object isExtensible() method
- The Object isFrozen() method
- The Object isSealed() method
- The Object keys() method
- The Object preventExtensions() method
- The Object seal() method
- The Object setPrototypeOf() method
- The Object values() method
- The Object hasOwnProperty() method
- The Object isPrototypeOf() method
- The Object propertyIsEnumerable() method
- The Object toLocaleString() method
- The Object toString() method
- The Object valueOf() method
- How to rename fields when using object destructuring
- How to send urlencoded data using Axios
- How to upload a file using Fetch
- How to use top-level await in ES Modules
- How to send the authorization header using Axios
- How to remove all the node_modules folders content
- How to get the first n items in an array in JS
- How to divide an array in multiple equal parts in JS
- How to load an image in an HTML canvas
- How to write text into to an HTML canvas
- How to fix the TypeError: Cannot assign to read only property 'exports' of object '#<Object>' error
- How to create an exit intent popup
- How to check if an element is a descendant of another
- How to force credentials to every Axios request
- Gatsby, how to change the favicon
- Loading an external JS file using Gatsby
- Parcel, how to fix the `regeneratorRuntime is not defined` error
- Object destructuring with types in TypeScript
- The Deno Handbook: a concise introduction to Deno 🦕
- Event bubbling and event capturing
- event.stopPropagation vs event.preventDefault() vs. return false in DOM events
- In which ways can we access the value of a property of an object?
- What's the difference between a method and a function?
- The importance of timing when working with the DOM
- Introduction to XState
- How to handle promise rejections
- How I fixed a "cb.apply is not a function" error while using Gitbook
- Gatsby, fix the "cannot find module gatsby-cli/lib/reporter" error