More than console.log
console.log()
can be used to print out strings and basic variables, but for rich objects, it can be useful to use console.table()
instead, passing it the variable you want to display.
console.dir()
is likewise useful for printing complex objects, HTML elements and event data.
console.error()
prints messages in the style of an error, making it easier to find them:
if (count > 1000) {
console.error('too many');
}
Usefully, console.error
gives you a stack track so you can find out how the code was executed. However, to properly signal an error and break execution of your code, you should throw an exception:
if (count > 1000) {
throw new Error('too many');
}
Read more
- Console (MDN)
Handling exceptions
Code can throw and exception when something goes wrong or say, you try to call a function with the wrong parameters. When the exception is thrown, execution stops in the given scope. For code running in the body of your Javascript file, this means nothing further will run in your code. If the error happens in a function, it means that nothing further within that function will run. Event handlers which are already registered will probably still work.
In the browser, exceptions show up with a red line of text. Usually you can expand the error to see what line of code it occurred on, and how that line of code was reached.
In Javascript, unlike some other languages, exceptions are pretty uncommon, and when they occur it's normally a sign that something needs to be fixed in your code.
It can be the case though that exceptions are happening in the course of normal operation, and you don't want your code to stop running. You can use try
. In the below example, we swallow exceptions, meaning we essentially ignore the error that occurs:
try {
// some lines of code which may throw an exception
} catch (e) {
// 'e' contains information on the error
}
// code continues to run...
This can be risky however. If you have multiple lines of code within your try
block, you won't quite know which line failed and which were properly executed. If those lines were operating on a variable defined outside of the block, it will be hard to reason what the value might be after the catch
allows execution to continue.
A safe pattern then is to only ever have one or two lines of code within your try
block in order to be more sure about the state of your code if an error happens.
Read more:
- Try catch (MDN)
Debugging Revisited
Now that a few more concepts have been illustrated, let's revisit debugging. Say you have a click handler which is supposed to turn an LED on or off:
document.getElementById("myButton").addEventListener("click", function() {
led.toggle();
});
But when you run it, nothing happens. How do you figure out what's going on? The first thing is to check the console to see if any errors show up just by loading the page. This is the first thing to fix.
If there are no errors but it doesn't behave the way you expect, ask yourself what the points of failure are.
In this simple example, these are some of the things that might be going wrong, in roughly the order you would check for them:
- Your script is not referenced properly; it never even loads
- Syntax errors prevents the script from properly excuting
- Your code which wires up the event is never called
- There is no HTML element with id "myButton"
- The HTML element with id "myButton" does not emit the event "click" when you expect
- The function "toggle" for variable "led" does not work
When starting to troubleshoot, it can be helpful to start with the broadest things that could possibly be wrong, verify they aren't wrong, and only then proceed to look at the details.
Ideally you use a proper debugger, but for quick and dirty debugging, you can print console messages in order to track down some of these points of failure:
console.log("About to wire up event");
document.getElementById("myButton").addEventListener("click", function() {
console.log("Calling toggle");
led.toggle();
});
If your code runs without error, but you don't see the "About to wire up event" message, you know that your code is not even executing, so you have to shift your attention to a higher set of concerns. If that message appears, and "Calling toggle" appears when you click the button, you know that it must be the toggle function itself which is not working the way you expect. If you get "about to wire up event" but you don't get "Calling toggle" when you expect, this would indicate that either the HTML element with that id doesn't exist, or it doesn't fire the "click" event when you expect, and you'll have to dig into that.
This is the basis of debugging misbehaviour. Reflecting on the points of failure, establishing the ground truth and devising ways of narrowing in on a particular part of code which doesn't act the way you expect.
You must try to identify the hierarchy of how things might fail, and know when to be more specific or more broad in trying to identify the point of failure.
If exceptions or syntax errors are reported, these are usually much easier to fix, because you'll get a line number of where the error occurred, and some indication of the nature of the error. Try to make sense of the error message. Ask yourself: what is this error about? what might be happening at this point for the error to occur? what insight do I need to understand how it could be going wrong? Again, printing out the value of variables before the faulty line of code can be very useful.
Syntax errors (which mean basically there is a typo in your code) can be difficult to track down, but are typically because you don't have a closing }
or )
. For novice programmers - and even experienced ones - it can sometimes be difficult to see the syntax error. To ease your burden, you could try using a code 'linter' or 'beautifier' to format your code and find syntax errors. (These can be installed as plugins to your code editor). Formatting of code, such as using indentation and being consistent can help you enormously in the visibility of errors, so try to be neat.
More debugging tools
To find out why something is running, add a console.trace()
line. When the interpreter hits it, it prints out the stack, showing the hierarchy of calls that lead to this line of code.
You can also pause execution of your code using the debugger
statement:
if (count > 5) {
debugger; // unexpected for count to go over 5, what's happening?
}
It can be useful at this point, when execution is paused, to use the browser's Javascript console to poke and prod at your running state. When you're happy, you can continue to the next line of code, or allow your code to resume normally.