Debugging with Node
Node has a wonderfuldebugger. As a front-end developer I’m mainly using Chrome’s tools but sometimes I run things in Node environment and this native feature comes handy. In this article we’ll see how to debug in the terminal using Node’s debugger.
When to use Node’s debugger
The native debugger is useful when we run Node programs trough the terminal and we want to see how they behave. We can run something in the console and expect what’s doing line by line. As most debuggers out there we have breakpoints, variable or expression watching, step-by-step execution.
How to run the debugger
All we have to do is addingdebug
to our command. Let’s get the following simple script:
// script.jsvar Counter = function (text) { this.text = text; this.data = { words: 1, letters: 0 }};Counter.prototype = { count: function () { for (var i=0; i < this.text.length; i++) { if (this.text.charAt(i) === ' ') { ++this.data.words; } else { ++this.data.letters; } } return this; }, print: function () { console.log('Words: ' + this.data.words); console.log('Letters: ' + this.data.letters); }};(new Counter('Debugging in Node')).count().print();
It’s a small program that counts the words in a sentence and all the characters but not spaces. If we run the program now we’ll get the following result:
Let’s assume that there is a problem with the script and we want to run it in debug mode. We have to usenode debug ./script.js
:
Now our program is paused at the very first line and the debugger expects our input. Notice that the debugger is listeninig on specific port. This means that we can control it remotely and that’s what (I believe)node-inspector is using.
Available commands
While we are in debug mode we have several commands available. Let’s use the example above and see the most popular ones.
Next step (next
orn
)
next
orn
is used for moving one step forward. In our case the second step in the program is the prototype definition. After that we reach the point where we create an instance of theCounter
class.
Notice the red arrows. They are showing where I typedn
and pressedEnter
.
Step in (step
ors
)
Just moving one step forward is not always enough. That’s becausenext step means next step but in the context of the current function. Sometimes we want to dive into another method. In such cases we usestep in command.
We usen
till we reach the line that creates an instance of ourCounter
class. Sendings
forces the debugger to jump inside theCounter
function.
Step out (out
oro
)
Once we finish inspecting a function we may want to go out and continue the program’s execution. Following the example above and sendingo
moves the debugger to thecount()
call.
Continue execution (cont
orc
)
When we debug complex applications we have lots of stuff happening. Very often we have long execution path and in order to reach the interesting part we have to pass several functions.next
command is not working well in such cases simply because we have to run it multiple times. It’s better to usecont
orc
. It tells to the debugger “Continue till you find a breakpoint”. We didn’t set any breakpoints so far so typingc
as a first command executes the whole program and we see the result.
Setting a breakpoint
To be honest I’m not using commands to set breakpoints. This is possible by usingsetBreakpoint()
orsb()
which sets a breakpoint at the current line. Same functions accept a line number so we can break at specific line. What I’m doing is addingdebugger;
statement in my code. This acts as a breaking point (it works in a browser too).
Let’s say that we want to inspect the loop that reads the words in my sentence. In the very beginning of thecount
function we adddebugger;
:
count: function () { debugger; // <---- breakpoint for (var i=0; i < this.text.length; i++) { if (this.text.charAt(i) === ' ') { ++this.data.words; } else { ++this.data.letters; } } return this;},
If we run the debugger it will pause at the first line of the script. Then pressingc
will instruct the debugger to continue till it finds a breakpoint or the program finishes.
Increase visibility
You probably noticed that we see just five lines of our program at a time. Sometimes we want to see more.list
command is exactly about that. It accepts a digit and that’s the number of the visible code lines. For example:
Watching
The last command that we’ll check in details iswatch
. It accepts an expression and it is printing it out at every debugging step. To illustrate how it works we’ll use the following expression:
watch("this.text.charAt(i)")
Of coursethis.text
doesn’t makes sense everywhere. It is available in thecount
function and that’s where it returns a proper value. In the first steps we just get<error>
displayed.
However, if we move forward and reach thefor
loop we’ll see the exact character read.
Other commands
There are some other commands which I personally don’t use. A full list of the available ones could be foundhere.
Alternatives
There are some other alternatives for debugging Node.js scripts. Most of the them involve GUI.