Sage-Code Laboratory
index<--

JavaScript Errors

During development, you run your JavaScript code often to find errors. This process is called debugging. A "bug" in programming is not an insect but an unexpected situation called "error" or "bug". To find them you need to test your code multiple times.

Page bookmarks:



Errors & Bugs

Logical errors: The most common technique to find JavaScript errors is to introduce a "spy". This is a line of code that display a message to console that you can investigate.If the message produce unexpected output, you are about to find an unexpected logical error.

Syntax errors: These errors are produced during runtime. Your code execute until a syntax error is encountered. Then the program is stopping its execution and you can read a usually red message about the error. For these kind of errors you do not need to create a "spy" statement.

Step by step: Sometimes the error is difficult to find. The last resort is to run a script step by step. This require to set a "breakpoint". This is not a script element it is a location (a statement number) that is flagged by the IDE with a red dot. When your script reach that specific point, it will suspend.

Inspection:  You can inspect values of variables (in scope) using using special window that can show the objects and the values from memory. After the inspection you can press a button and the script can resume running one step at a time or it can run up to next "breakpoint" depending on the button you use.

Using Console

The console in JavaScript is a powerful tool that can be used to debug your code, log information, and interact with the browser. It is a property of the window object, and it provides a number of methods that can be used to output text, objects, and other data to the browser console.

Method Description
console.log() Writes a message to the console.
console.info() Writes an informational message to the console.
console.warn() Writes a warning message to the console.
console.error() Writes an error message to the console.
console.clear() Clears the console.
console.assert() Tests if an expression evaluates to true.
console.count() Increments a counter, printing the counter name and value.
console.time() / console.timeEnd() Measures the time taken between calling time and timeEnd.

Example:

/*spy demo*/
{ let x = 5, y = 10;
  console.log(x,y) //first spy
  x++
  y++
  console.log(x,y) //second spy
  x++
  y++
  /* better output */
  console.log("x = ",x)
  console.log("y = ",y)
}

Debug Tools

You can debug JavaScript in Browser. Your script is preloaded when you visit a web page.If your code is stored as a script file, you can load the script using browser and debug it by `following these steps:

Chrome debug in console.

  1. Hit the F12 key or Ctrl+Shift+I;
  2. Select the Scripts , or Sources tab;
  3. Select "js/test.js" script from the tree;
  4. Add a breakpoints by clicking on the line number;
  5. Click this link to execute: test()
  6. Use F11 to run step by step.
  7. Click Console tab to see the messages.

Responsive Image

Chrome Console Source


Firefox debug in console.

  1. Hit the F12 key or Ctrl+Shift+I;
  2. Select the Debugger tab;
  3. Select "js/test.js" script from the tree;
  4. Add a breakpoints by clicking on the line number;
  5. Click this link to execute: test()
  6. Use F11 to run step by step.
  7. Click Console tab to see the messages.
Responsive Image

Firefox Console Debugger

Errors and Pitfalls

Best Practices

Proactive Programming

Instead of waiting for error to happen, a good developer can prevent the situation by checking some conditions before performing the computations that can fail. This is called proactive error handling and is the best method to avoid probable errors.

Use Type Checking


 function add(x, y) {
 // Type check inputs 
  if (typeof x !== 'number' || typeof y !== 'number') {
    throw new TypeError('The arguments must be numbers!');
  }
  
  return x + y;
 }   
 

Use Default Parameters


 function add(x, y=0) {
  return x + y;
 }
 

Using Assert()

The assert() method helps avoid errors by checking if a condition is true. If not, it throws an AssertionError.


function assert(condition, message) {
  if (!condition) {
    throw new Error(message || 'Assertion failed!'); 
  }
}

function square(n) {
  assert(typeof n === 'number', 'n must be a number!');
  
  return n * n;
}

square(4);  // Returns 16
square('2'); // Throws Error

We can also provide a custom error message:


function divide(a, b) {
  assert(b !== 0, 'Attempted to divide by zero!');
  
  return a / b;  
}

divide(4, 2);  // Returns 2
divide(4, 0);  // Throws custom Error

Exceptions

Exceptions are abnormal situations that can cause a computer program to malfunction, produce unpredictable or incorrect results.In this case the application should report an error message and interrupt itself or at least verify the situation and decide to stop or continue.

Producing exceptions

An exception can be created by the system when a statement can not be executed properly. You can also create exceptions on purpose. Usually you check a condition and decide before producing an exception. Most elegant is to produce an Error object as exception, but JavaScript enable you to produce an exception using any value. The example below will use keyword: throw to create an exception.

Example:

// create exception object
throw new Error("You got an exception")
// create exception with a string object
throw "You get an exception!"
// create exception with a number object
throw -1

Homework: Run the example above. This example will stop on first statement, but you can comment statements one by one to check the effect of each individual case. The script will stop and you get an error message similar to this:

error: Uncaught -1

Resolving exceptions

Unresolved exceptions cause script to stop and produce an error to console, but your web-page will usually continue working with defects. To avoid these defects you must do proactive programming. This means you must check conditions and handle errors to avoid "Uncaught Exceptions".

For resolving exception you can use a special "control flow" statement that is called "try". It is a multi-block statement with several regions: The main block start after "try" keyword. You can use "catch blocks" to resolve several potential errors and "finally" block to execute after error is resolved.

Example:

try {
   throw 'error';
}
catch (e) {
   console.error(e);
}
finally {
   console.log('done')
}

Notes:

If you use: console.error() instead of console.log, the console will probably print your error message with red color. You can use a function to do something with the error. Usually you log the error and continue program execution. Handler

The catch statement has a handler that is created automatically. You can specify this handler name in parenthesis after catch keyword. In our case the exception handler is: e. Handler type depends on your throw statement. If you create an Error object the handler will represent the object. In our case, e is of type 'string'.

Conditional Catch

You can create different catch statements using a conditional. Notice though this is very new and it may bot be supported by many engines. Check with your team before you use this syntax.

Pattern:

Next is "pseudo code" fragment to demonstrate "conditional catch" design pattern.

try {
   myroutine(); // may throw three types of exceptions
} catch (e if e instanceof TypeError) {
 // statements to handle TypeError exceptions
} catch (e if e instanceof RangeError) {
 // statements to handle RangeError exceptions
} catch (e if e instanceof EvalError) {
 // statements to handle EvalError exceptions
} catch (e) {
 // statements to handle any unspecified exceptions
 logMyErrors(e); // pass exception object to error handler
}

Finally Block

The finally block is executed no matter what. In this block you can close a resource or log a message. When in this block you do not know if there was an error or not, but this code is guaranteed to be executed in any case.

Pattern:

Next pattern demonstrate how to handle resources using try – finally block.

open_resource();
try {
   use_resource(my_data);
}
finally {
   close_resource(); // always close the resource
}

JavaScript Error

The Error instance must be created using "new" operator like any other object. You can create an exception object and "throw" the object later once or several times, depending on your programming logic. Also you can create the object anonymously and give it a name later using "catch".

Example:

// named exception
let exception = new Error('my exception');
// create a named exception
try {
   throw exception
}
catch (e) {
   if (e instanceof Error) {
      console.error(e.message);
   } else {
      console.log("unexpected exception");
   }
}
// your program can continue
console.log("continue program")

To learn more about Error object read the reference:  MDN Error


Caution: Next example demonstrate a common error in JavaScript: Using relation operators with two objects will compare object references and not object attributes or values they represent. Read the example and wander how is this possible. JavaScript is not perfect and sometimes difficult to explain.
/* create non null Boolean object */
var a = Boolean(false); // boolean
var b = new Boolean(false); // object
console.log(a === false) //true (expected)
console.log(b === false) //false (unexpected)
// a is "boolean" works as expected
if (a)
  console.log("a is true");
else
  console.log("a is false"); //expected
// b is "object" works in unexpected way
if (b)
  console.log("b is true"); // unexpected
else
 console.log("b is false");

Read next: Website