Debugging Node Applications
Marcell Cruz
Posted on September 2, 2020
Let's start with an example file so we can test it out, create a file called "test.js" and insert the following code.
let x = 5;
debugger;
console.log(x);
Now we can run it with the "inspect" keyword
node inspect test.js
The debugger will stop in the first line of code, as you can see in the picture. The little arrow > represents where you're right now, and you can also see some code around it, if you ever find yourself lost, type list(10) and hit enter to show 10 lines around where you are, you can increase the number of lines to have a better view of the code.
From here you can type:
- c to continue, this will make the debugger stop in the next "debugger" keyword.
- n, to move to the next line or next debugger keyword(more on this later). now type n to move out of the declaration of the variable "x".
Inspecting variable values
You can inspect variables values by typing "exec " in our case we want to know the value of the variable x, so we type exec x and hit enter
You can use exec to run and print any code that you want. For example, you might wanna know the result of x + 5, you can type it in exec x + 5 and hit enter to see the result
Nothing that you type in the debugger will change your code in any way so you can play around and do whatever you want. In this case, the result will 10 of course. You use the exec call to do any type of complex code execution with the value of your variables, functions anything..., to identify bugs and test possible solutions to your code, let's see a more concrete example.
Using code inspection to write code.
Create a file named "test2.js" and place the following code
let users = [
{
id: 1,
name: 'John'
},
{
id: 2,
name: 'Mary'
}
];
const findUser = (users, userName) => {
return users;
}
So now let's say you wanna write this "findUser" function but you don't know exactly how to do it, or what it will be the best way of doing it.
We can use the node inspect to test things out quickly and finish writing our findUser function.
node inspect test2.js
Now press "n" until you get where the findUser function is being called.
Here you can test different expressions quickly to find the best way to implement what you want. Let's say you had the idea to use "filter" but you're not sure how to do it, using exec you can quickly play around with the users variable and arrive to the solution, which would be something like this.
exec users.filter(user => user.name == 'John')[0]
and you can also of course check the results in real-time.
The advantage of doing this over just writing the code in the file, is that you considerably reduce the feedback loop of writing something and see the result which will in turn decrease the time that you take to write code. Not only that and much more important is that you have the correct "state" of the app, so you don't need to keep in your mind the state of the app at that moment, you can just write the code that you think will solve the problem, and see the result for yourself.
The REPL(Read, Evaluate, Print Loop)
The REPL is a just an easier way to do what we did above without having to write exec all the time, you can enter the REPL by typing repl and hitting enter, and you can exit by pressing CTRL+c, the picture below is the same thing that we did before but using the repl instead of running exec.
Using watchers
The last useful piece to debug your code is using watchers, watchers are just a more convenient way to check the values of an expression, the following code is just a simple function that changes the balance of the user. Create a file called test3.js and place the following code.
let users = [
{
id: 1,
name: 'John',
balance: 100
},
{
id: 2,
name: 'Mary',
balance: 200
}
];
const changeBalance = (userId, amount) => {
for(let user of users) {
if(user.id === userId) {
user.balance += amount;
break;
}
}
};
changeBalance(1, 100);
changeBalance(2, 100);
changeBalance(2, -100);
changeBalance(1, -200);
As we did before run this file with
node inspect test3.js
The code will stop in the first line as expected, now we can create a watcher to watch the balance of the users, let's say we want to watch how John's balance changes over time.
You can pass any expression to the "watch" function, we know that John is the first user in the array so if we want to watch how his balance changes over time we can write
watch('users[0].balance')
and hit enter, you should see something like this
Now every time you use any command to change the line where you're in the debugger a new item will appear on top of the debugger with the resulting values of all the watchers that you've created until now
In the above image, you can see that the line "0:" represents the watcher that you've created, "users[0].balance = 100" so John starts with 100 dollars in his balance, you can keep pressing n to go through the code and every time the debugger moves the expression will be re-evaluated with the current value if you also want to watch how "Mary" balance changes over time you can create a watcher for her just like you did for John
watch('users[1].balance')
If you don't want to watch the expression anymore you can unwatch the expression with unwatch('users[0].balance') in John's case.
You can also debug with Chrome DevTools but I wouldn't recommend it because it's harder to set up slower and adds no real advantage, If you're interested in learning more you can read more about it here.
Have a great day 😄
Posted on September 2, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 22, 2024