Error Handling in JavaScript

Errors are inevitable. If you are a programmer you must have seen different types of errors. Whenever something goes wrong, JavaScript engines notify us in form of errors and exceptions. It is very important to handle those errors and exceptions correctly. For example, in front-end applications, you don't want to leave the user with a red screen with some gibberish written all over the screen or a blank screen. It is as much important to handle the error as to handle happy paths in our applications. So let start.

What is Error?

Error is a special objects in JavaScript which has a bunch of information about the error that occurred like where the error occurred, at which line, what is the error message, what is the type of error etc.

const err = Error("Something bad happened!");

Other than this generic Error, there are different types of errors defined by the JavaScript language. Some of them are -

  1. TypeError
  2. SyntaxError
  3. ReferenceError and so on.

The above listed are the most common types of errors faced.

const name = "Apple";
name = "Banana";        // TypeError: Assignment to constant variable.

What is an exception?

An Error object when thrown is called an exception.

Handling Errors

try...catch...finally is used to handle errors in JavaScript.

try {
    // Any code that might throw some error
} catch(error){
    // Handle the thrown error
} finally {     // finally is optional
    // Do some operation like remove database connection.
}

There is one important point to note here is that any code after the line which throws an error is not executed and control directly jumps to the catch block.

An error that is not handled by the developer will be ultimately handled by the JavaScript engine and shown on the console.

Handling Error in synchronous code

Handling errors in synchronous code is very simple because the control flow is very clear to understand in synchronous code. Just use simple try...catch. For example -

function someFunction() { 
    throw Error("Error in Synchronous code");
}

try {
    someFunction();
    console.log("After error is thrown");   // this will not be executed
} catch(error) {
    console.log(error.message);    // Error in Synchronous code
}

Handling Errors in asynchronous code

This is tricky because the control flow is different in the case of asynchronous code. For example -

function someFunction() { 
    setTimeout(function() {
        throw Error("Error in Asynchronous code");
    },2000)   
}

try {
    someFunction();
    console.log("After error is thrown");  // this will not be executed
} catch(error) {
    console.log(error.message);   
}

If you do something like this, the error won't be handled because when the anonymous function inside setTimeout will execute and throw an error, the try...catch block would have been removed from the call stack a long ago. So it won't be handled. The easy way to solve this is to put the try-catch inside the setTimeout function itself like this -

function someFunction() {
    setTimeout(function() {
        try {
            throw Error("Error in Asynchronous code");
        } catch(error) {
             console.log(error.message);   
        }
    },2000)   
}
someFunction();

JavaScript has better ways to deal with this using Promises and async/await which is more intuitive.

Handling Errors in Promise

To handle the error in the above code using promise. We can do something like this -

const someFunc= new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(Error("Error in Asynchronous code"));
    }, 3000);
});
someFunc().catch(error) {
    console.log(error.message);
};

This does the same thing but is more readable and intuitive.

Handling Errors in Async/Await

Error handling in async/await feels like error handling in synchronous code. We use the same try..catch block here. So it even more intuitive than error handling in Promises.

const someFunc= new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(Error("Error in Asynchronous code"));
     }, 3000);
});

async function handlingErrorInAsyncAwait() {
    try {
        await someFunc();
    } catch(error){
        console.log(error.message);
    }
}

You see this. Really simple. I had to create a new function handlingErrorInAsyncAwait because we can use await only inside the async function.

This is the most general idea of how we do error handling in JavaScript. I hope you would have learned something new today.

Have a good day🙂