During the development of any program (including JavaScript programs), you’ll make the odd mistake. This is normal and part of everyday life when you write programs.
It’s more important to know how to find and rectify errors quickly—and it’s even better to know how to avoid mistakes.
These may be syntax errors (i.e., notations of incorrect or incomplete JavaScript statements), but there may also be logical errors (in which your program is running perfectly but is not producing the results you expect).
Developing a Program
You should proceed step by step. First, give some thought to how the entire program should be structured, and do it on paper. Which parts should it consist of, in sequence? Don’t try to write the entire program with all its complex components at once. This is the biggest mistake you can make at the beginning—or sometimes even later!
First, write a simple version of the first part of the program, and then test it. Don’t add the subsequent program section until you’ve performed a successful test, and test again after each change so that if an error occurs, you’ll know that it was caused by the last change. After the last addition, you will have created a simple version of your entire program.
Now, change part of your program to a more complex version. In this way, you’ll make your program more complex step by step until you have finally created the entire program as it corresponds to your initial considerations on paper.
Sometimes, one or two changes to your design arise during the actual programming process. This is not a problem as long as the entire structure doesn’t change, but if it does change, then you should return to your papers briefly and reconsider the structure. This doesn’t mean that you have to delete the previous program lines, but possibly, you can just change them a little and arrange them differently.
Write your programs clearly. If you are thinking about how you can write three or four specific steps of your program at once, turn them into individual statements that are executed one after the other. This simplifies any troubleshooting process, and if you (or another person) change or expand your program at a later date, it will be much quicker to start building the program.
When it comes to branches and loops: Have you closed all the brackets and parentheses you have opened? That’s a classic programming error that often leads to nothing being displayed at all, especially with JavaScript.
You can put individual parts of your program in comment brackets to determine which part of the program runs without errors and which part does contain errors.
Finding Errors Using onerror
One way to find errors is to use the onerror event. As soon as certain errors occur, the event gets triggered, and a function is called that provides you with information about the error. Let’s take a look at the following example:
...
<body><p>
<script>
const y = 42;
document.write(x + "<br>");
document.write(y + "<br>");
</script></p>
</body></html>
The values of the two variables should be displayed on the screen, but the x variable never gets declared. The attempt to output x results in the program being aborted, which means that the value of the correctly declared y variable will no longer be output either. The screen remains blank and the cause remains unknown.
So, let’s now extend the program for troubleshooting purposes:
... <head> ...
<script>
function error_handling(error, file, line)
{
alert("Error: " + error + "\nFile: " + file
+ "\nLine: " + line);
}
</script>
</head>
<body><p>
<script>
onerror = error_handling;
const y = 42;
document.write(x + "<br>");
document.write(y + "<br>");
</script></p>
</body></html>
The onerror event occurs when an error occurs, and as a result, the function that was assigned to the event gets called. In this example, that’s the error_handling() function. Functions are usually defined in the head of the document, and the error_handling() function is provided with information about the error that has occurred, which you can output using alert().
The message for our example is shown in the figure below, and it’s referred to as an Uncaught ReferenceError. A reference error occurs if no reference (i.e., no declared name) exists for a variable. Errors can be caught, but this error is not caught. It occurs in line 18 of the onerror.htm file, and thanks to this message, the cause of the error can be found and the problem can be solved.
Exception Handling Using try ... catch
Exception handling using try ... catch enables you to prevent your program from aborting. If you suspect that errors may occur in certain parts of the program due to inputs or other causes, you can place the relevant program parts in a try block.
If an error actually occurs, the program branches to a catch block in which the error is caught. An error message can be displayed there, or alternative statements can be run that avoid the consequences of the error.
If no error occurs, the statements in the try block are processed normally and the catch block is skipped. There may also be a finally block that’s processed in each case, and this applies whether an error has occurred or not. Curly brackets must always be written, even in the case of a single statement.
Here’s an example:
...
<body><p>
<script>
const y = 42;
try
{
document.write(x + "<br>");
document.write(y + "<br>");
}
catch(e)
{
alert(e);
}
finally
{
document.write("This will definitely be done<br>");
}
</script></p>
</body></html>
The values of the two variables are to be output in the try block. The missing declaration of x is noticed, the program branches to the catch block, and information on the error that has occurred is transmitted in an error object. It has become common practice to designate such an error object with e (for error), and you can output the object using alert().
The output in the figure below contains a ReferenceError. In contrast to the previous program, the error has been intercepted, which is why Uncaught doesn’t appear and the program continues to run.
Throwing Exceptions Using throw
You can also create your own error situations in which an exception can be thrown by using throw. You benefit from the exception handling process, which ensures that the program branches to the catch block.
In the following example, a number greater than 0 is to be entered. There are supposed to be two situations that count as errors:
- The entry is not a valid number.
- A number is entered that’s too small.
In both cases, a matching error message is to be displayed.
Here’s the program:
...
<body><p>
<script>
const number = parseFloat(prompt("Please enter a number > 0"));
try
{
if(isNaN(number))
throw "No valid number";
if number <= 0:
throw "Number too small";
document.write("Number: " + number);
}
catch(errorObject)
{
alert(errorObject);
}
</script></p>
</body></html>
If one of the two situations occurs, then it is recognized thanks to the branch. The throw statement ensures that the program branches directly to the catch block, and at the same time, an associated error message is sent to the catch block. This message is output, and in the figure below, you can see the message that displays if you enter the value -5.
Debugging a Program
In modern browsers, you have the option of debugging your programs. Debugging helps you to find logical errors, and you can run your programs step by step and view the values of all variables at any point in time. We show this in this section using the example of the Google Chrome browser.
As an example, a program in the chrome_debug.htm file is used in which two numbers are added. In the next figure, you can see the default output of the program.
When you initiate debugging, it’s assumed that the browser is open with the named program. Open the browser menu using the three dots in the top right-hand corner and select the More tools > Developer tools menu item. Then, the developer tools are displayed, and they may offer many different options.
For debugging, you want to select the Sources tab at the top of the screen. The program code is displayed as shown below, and the individual lines are preceded by line numbers.
After you click on one of the line numbers, a breakpoint is created for this line. A second click removes the breakpoint. In the next figure, you can see that breakpoints have been created next to the lines in which the b and output variables receive their values.
After reloading the document, the program doesn’t run through completely but stops before executing the line in which the first breakpoint was set. The a variable has already been assigned a value at this point, and the other variables haven’t yet.
You can monitor the values of the variables farther down in the Watch tab. To show the variables, click the button with the + sign, enter the name of the respective variable, and press (Enter).
In the next figure, you can see the status after stopping the program, after all four variables of the program have been displayed.
You can continue the execution of the program via the Resume Script Execution button, which you can see on the left above the Paused on breakpoint text. (Alternatively, you can press (F8).) You use this button to continue the program to the next breakpoint, if available, or to the end of the program. In this next figure, you can see the situation when you reach the second breakpoint.
Up to this point, the b and c variables have also been assigned values, and after the next resume, the program runs to the end and the output appears. After removing the breakpoints, the program runs again without stopping.
Learn more about JavaScript debugging in this post.
Editor’s note: This post has been adapted from a section of the book Getting Started with JavaScript by Thomas Theis.
Comments