# Errors and Error Handling in JavaScript 

In most programming languages, when we write code and make a mistake, we are immediately warned, and if it is not a runtime error, the program doesn't even begin execution. However, in this aspect, JavaScript is different. JavaScript had already been designed to throw as few errors as possible. This is because it was designed to run in the browser. Therefore, it could not afford to throw errors at every step and cause a bad user experience.

For example, JavaScript would not throw an error if we did:

```javascript
const ans = '5'*2;
```

It would store 10 as the result. But in some cases, where JavaScript cannot handle the problem, like:

```javascript
const ans = null.map();
```

Since null does not have a map property, it throws a TypeError.

Therefore, JavaScript throws an exception (word used interchangeably with error) only when the given set of instructions literally cannot be made to execute in any defined manner. And even in that case, it is possible to stop JavaScript from throwing an exception.

## Understanding Errors

In JavaScript, errors are no exception. YES! These are also objects. An error is a special type of object that is instantiated either from an Error Class or a Class that extends it. Most of the time, the errors that we can work with are runtime errors only because these are the only ones that JavaScript can actually catch. If the runtime error is of a particular defined type, then that type of error can be thrown; else, the general Error class object can be thrown with a relevant message.

The different types of predefined error classes that extend the Error Class are:

**EvalError**

```plaintext
Creates an instance representing an error that occurs regarding the global function eval().
```

**RangeError**

```plaintext
Creates an instance representing an error that occurs when a numeric variable or parameter is outside its valid range.
```

**ReferenceError**

```plaintext
Creates an instance representing an error that occurs when de-referencing an invalid reference.
```

**SyntaxError**

```plaintext
Creates an instance representing a syntax error.
```

**TypeError**

```plaintext
Creates an instance representing an error that occurs when a variable or parameter is not of a valid type.
```

**URIError**

```plaintext
Creates an instance representing an error that occurs when encodeURI() or decodeURI() are passed invalid parameters.
```

**AggregateError**

```plaintext
Creates an instance representing several errors wrapped in a single error when multiple errors need to be reported by an operation, for example by Promise.any().
```

**InternalError Non-standard**

```plaintext
Creates an instance representing an error that occurs when an internal error in the JavaScript engine is thrown. E.g. "too much recursion".
```

The error object stores information about the error and is presented on the console to indicate the throw of an exception. The most important property is the message property. It contains the human-readable cause of the occurrence of the error. It is frequently used for debugging or even client-side error display, depending on the use case. We can also define our own errors that must extend the Error class so that they can be thrown.

## Error Behavior

Errors in JavaScript behave differently based on the environment in which the code is actually running. This is because different environments have different priorities. Therefore, while the action of throwing an error remains the same, it affects the environment differently.

### Browser

In the browser, the event loop executes each task separately. The main priority of the browser is not to stop execution so that the page doesn't hang and the user gets a good experience. Therefore, if any task throws an error, the error is logged, and the task is discontinued by the event loop as it picks up the next task.

### Node.js

In Node.js, we deal with operating systems, servers and other sophisticated forms of code. Here, we need to prioritise correctness over continuation. Therefore, if any task throws an exception and it is not caught, the system throws an exception and discontinues the process itself instead of just discontinuing the task. This is because an unexpected error can corrupt the system.

### Try Catch

Many times, in aavaScript code, we know that an error can occur. This error, in some cases, is even a desirable outcome. However, if such an error occurs, the task will terminate. When we want that even if an error occurs, the task continues execution, and we handle the errors ourselves instead of terminating the program. To accomplish this, JavaScript has provided us with the try-catch syntax.

**The syntax looks like this:**

```javascript
try{ 
//Code that can throw error 
}catch(error){
 //Handling that error [Ex: We can print the error] 
}
```

In the try block, we put in the code segment that can throw an error. If any statement throws an error, the remaining statements are not executed and the control flow shifts to the catch block.

### Catch Block

The catch block is an optional entity after the try block. It is used to handle errors or execute some code based on information about that error. It is important to note that any error thrown in the catch block will not be caught. These errors will behave the same as outside the try catch block and stop the execution of the program. Let us explore what we can do with the errors in the catch block.

At first, we receive the error object, which is passed from the try block. The error is received in this syntax:

```javascript
catch(error)
```

If one does not want to catch the error but simply take action in the event of the occurrence of an error, we can omit this syntax and simply write:

```javascript
try{ 
// Error prone code 
}catch{ 
//Task to do if an error is thrown
}
```

We omit the error variable and the parentheses around it.

When we get the error, the most common use case is to just log the error for us to debug the code.

```javascript
try{
 // Error prone code 
}catch(error){
 console.log(error); 
//We can only print the error message too using: console.log(error.message);
}
```

We can also handle the error conditionally. For example, we can check if the error is an instance of a certain type of error. Based on the desired behaviour, we can also rethrow an error or throw a new error within the catch block.

```javascript
try{ 
// Error prone code 
}catch(error){
if(error instanceOf TypeError)
{
throw new Error('Something serious has broken and its the types'); 
}
}
```

### The finally Keyword

The finally keyword is used to define a section of code that will execute regardless of the fact whether an error occurred or not, provided the control flow entered the try block. The finally block is written after the try or the optional catch block if it is present. For example:

```javascript
try{ 
  throw new Error('Very bad happened');
 }finally{
 console.log('Everything is either fine or it will be fine'); 
}
```

Or:

```javascript
try{ 
throw new Error('Very bad happened'); 
}catch(error){ 
console.log(error); console.log('A problem occurred'); console.log('Working on Repairs'); }finally{ console.log('Everything is either fine or it will be fine');
}
```

The most practical use case of the finally block is seen when we are working on a code section that uses a resource, like a database connection or a file stream. We could want that when this task completes or fails, the fact that the connection was closed to ensure consistent behaviour is established. So we can do something like:

```javascript
try{ 
const result = await db.query(sql);
 }catch(error){ 
console.log("An error occurred",error);
 }finally{ 
  db.release(); 
}
```

This code ensures that the DB connection is released in case an error occurs.

## Custom Errors

In JavaScript, we can also create our own custom errors. Such errors can either be created directly using the Error class constructor and passing a custom error message, or we can generalise this by creating our own error class that extends the existing Error class. For example:

```javascript
class ApiError extends Error{
 constructor(message){ 
this.message= message;
 this.name = 'ApiError';
} }
```

To throw a new error of any type, we use the throw keyword. The syntax to throw an error from the code is:

```javascript
throw (error object)
```

The error object is usually instantiated in time by using the new keyword. Like:

```javascript
throw new ApiError('API Down');
```

### Conclusion

Error handling is a core part of JavaScript, and without understanding errors properly, it becomes increasingly difficult to debug code. Getting a good grasp on what errors are and the different ways to handle those errors helps us understand code more deeply.
