Rayhan Mahi
4 min readMay 6, 2021

--

Errors are part of the programming journey. By producing errors, we actually learn how not to do something and how to do it better next time.

In JavaScript, when code statements are tightly coupled and one generates an error, it makes no sense to continue with the remaining code statements. Instead, we try to recover from the error as gracefully as we can. The JavaScript interpreter checks for exception handling code in case of such errors, and if there is no exception handler, the program returns whatever function caused the error.

This is repeated for each function on the call stack until an exception handler is found or the top-level function is reached, which causes the program to terminate with an error.

In general, exceptions are handled in two ways:

  1. Throw an exception — If there is a problem that can’t be handled meaningfully where it occurs at runtime, it’s best to throw it
  • function openFile(fileName) { if (!exists(fileName)) { throw new Error(‘Could not find file ‘+fileName); // (1) } … }
  1. Catch an exception — Thrown exceptions are caught and handled at the place where they make more sense at runtime
  • try { openFile(‘../test.js’); } catch(e) { // gracefully handled the thrown expection }

Let’s dive into these actions in more detail.

Throw an exception

If you’ve been using JavaScript for a long time, you may have seen something like ReferenceError: fs is not defined. This represents an exception that was thrown via a throw statement.

Syntax

throw «value»;
// Don't do this
if (somethingBadHappened) {
throw 'Something bad happened';
}

There is no restriction on the type of data that can be thrown as an exception, but JavaScript has special built-in exception types. One of them is Error, as you saw in the previous example. These built-in exception types give us more details than just a message for an exception.

Error

The Error type is used to represent generic exceptions. This type of exception is most often used for implementing user-defined exceptions. It has two built-in properties to use.

1. message

This is what we pass as an argument to the Error constructor — e.g., new Error('This is the message'). You can access the message through the message property.

const myError = new Error(‘Error is created’)
console.log(myError.message) // Error is created

2. stack

The stack property returns the history (call stack) of what files were responsible for causing the error. The stack also includes the message at the top and is followed by the actual stack, starting with the most recent/isolated point of the error to the most outward responsible file.

Error: Error is created
at Object. (/Users/deepak/Documents/error-handling/src/index.js:1:79)
at Module.compile (internal/modules/cjs/loader.js:689:30)
at Object.Module.
extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
at startup (internal/bootstrap/node.js:266:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:596:3)

Note: new Error('...') does not do anything until it’s thrown — i.e., throw new Error('error msg') will create an instance of an Error in JavaScript and stop the execution of your script unless you do something with the Error, such as catch it.

Catch an exception

Now that we know what exceptions are and how to throw them, let’s discuss how to stop them from crashing our programs by catching them.

try-catch-finally

This is the simplest way to handle the exceptions. Let’s look at the syntax.

try {
// Code to run
} catch (e) {
// Code to run if an exception occurs
}
[ // optional
finally {
// Code that is always executed regardless of
// an exception occurring
}
]

In the try clause, we add code that could potentially generate exceptions. If an exception occurs, the catch clause is executed.

Sometimes it is necessary to execute code whether or not it generates an exception. Then we can use the optional block finally.

The finally block will execute even if the try or catch clause executes a return statement. For example, the following function returns false because the finally clause is the last thing to execute.

function foo() {
try {
return true;
} finally {
return false;
}
}

We use try-catch in places where we can’t check the correctness of code beforehand.

const user = '{"name": "Deepak gupta", "age": 27}';
try {
// Code to run
JSON.parse(params)
// In case of error, the rest of code will never run
console.log(params)
} catch (err) {
// Code to run in case of exception
console.log(err.message)
}

As shown above, it’s impossible to check the JSON.parse to have the stringify object or a string before the execution of the code.

Note: You can catch programmer-generated and runtime exceptions, but you can’t catch JavaScript syntax errors.

try-catch-finally can only catch synchronous errors. If we try to use it with asynchronous code, it’s possible that try-catch-finally will have already been executed before the asynchronous code finishes its execution.

--

--