An exception indicates the occurrence of an unusual situation that necessitates specific handling methods. Within the realm of programming, an exception represents an irregular piece of code that disrupts the standard execution flow. These exceptions demand the use of particular programming structures designed for their management.
What is Exception Handling?
In the realm of programming, exception handling refers to a systematic approach employed to manage unexpected statements within the code and ensure their execution. This mechanism also facilitates the regulation of control flow within the code or program. To effectively manage the code, different types of handlers are utilized, which are responsible for processing exceptions and executing the necessary code. For instance, performing a division of a non-zero number by zero will invariably yield infinity, which constitutes an exception. Therefore, through the implementation of exception handling, such scenarios can be managed and appropriately addressed.
The throw statement serves the purpose of raising an exception. This indicates that when an unexpected situation arises, an exception is triggered using throw. The exception that is raised is managed by enclosing the code within a try…catch block. If there is an error, the catch block will be executed; otherwise, only the statements within the try block will run.
Consequently, within a programming language, various categories of errors may arise that can disrupt the correct functioning of the program.
What is a JavaScript Error?
A JavaScript error refers to a problem that hinders the code from executing properly. Such errors can arise during the website development process due to a developer's oversight, including programming errors, invalid input, or various other issues that result in a malfunction within the program.
Types of Errors:
When programming, you may encounter three distinct categories of errors in your code:
- Syntax Error: When a user makes a mistake in the predefined syntax of a programming language, a syntax error may appear.
- Runtime Error: When an error occurs during the execution of the program, such an error is known as a Runtime error. Code that creates runtime errors is known as an Exception . Thus, exception handlers are used for handling runtime errors. It includes TypeError , ReferenceError, RangeError, etc.
- Logical Error: An error that occurs when there is any logical mistake in the program that may not produce the desired output, and may terminate abnormally. Such an error is known as a Logical error. It includes wrong conditions, wrong variable usage, etc.
Error Object
When a runtime error takes place, it generates and throws an Error object. This object can also serve as a foundation for exceptions defined by users. An error object consists of two key properties:
- name: This property of the object is responsible for setting or retrieving the name of the error.
- message: This property provides an error message presented as a string.
JavaScript offers a variety of standard built-in error types, commonly referred to as error constructors. To grasp the specifics of each error type, we will illustrate them with pertinent examples:
- SyntaxError: An instance of this error is generated when a syntax issue arises during the parsing of the eval function.
Example:
Let's take an example of SyntaxError.
Example
try {
eval('var a = ;'); // This line has a syntax error
} catch (error) {
console.log(error instanceof SyntaxError);
console.log(error.name);
console.log(error.message);
}
Output:
true
SyntaxError
Unexpected token ';'
Explanation:
In the preceding code snippet, we managed the error by employing a try-catch construct. We defined a try block where the eval function attempts to evaluate a string written in JavaScript. In this instance, 'var a = ;' constitutes invalid syntax. Consequently, it generates a syntax error, which is then captured by the catch block and assigned to the variable named error.
- EvalError: This creates an instance of the error that was triggered within the eval function, which is a global method utilized for evaluating JavaScript strings.
Example:
Let's have an example of EvalError.
Example
try{
throw new EvalError('An EvalError has occurred');
} catch (e) {
console.log(e instanceof EvalError);
console.log(e.message);
console.log(e.name);
};
Output:
true
An EvalError has occurred
EvalError
Explanation:
In the preceding example, we addressed an error by employing a try-catch statement. We initiated a try block where we utilized throw new EvalError accompanied by a custom message. In this scenario, the raised error is assigned to the variable e. The statement console.log(e instanceof EvalError) is included to verify whether the caught error is an instance of EvalError. If this condition holds true, it outputs true. Additionally, console.log(e.message) displays "An EvalError has occurred," while console.log(e.name) reveals the name of the error along with its type.
- RangeError: This creates an instance of the error that is triggered when a numeric variable or parameter falls outside of its permissible range.
Example:
Let's take an example of RangeError.
Example
let numRange = (num) => {
if (num < 30) throw new RangeError("It is wrong Number");
return true
}
numRange(20);
Output:
Runtime Error:
/box/script.js:2
if (num < 30) throw new RangeError("It is a wrong Number");
^
RangeError: It is a wrong Number
Explanation:
In the preceding illustration, we established an arrow function referred to as numRange. This function evaluates whether the specified number is less than 30. If the condition holds true, it generates a RangeError accompanied by the message "RangeError: It is a wrong Number." When we invoked the function with the value of 20, the condition evaluated to true. Consequently, the error was triggered, revealing the rationale behind it.
- ReferenceError: This error generates an instance when an attempt is made to dereference an invalid reference.
Example:
Let's look at an example of ReferenceError.
Example
console.log(abc);
Output:
Runtime Error:
/box/script.js:1
console.log(abc);
^
ReferenceError: abc is not defined
Explanation:
In the preceding example, the line of code console.log(abc) resulted in an error due to the fact that it had not been defined prior to its usage. This error is categorized as a ReferenceError.
- TypeError: This type of error occurs when a variable is assigned a type that is not considered valid, thereby generating an instance specifically for this error.
Example:
Let's have an example of TypeError.
Example
let myNum = 30;
console.log(myNum.split(""));
Output:
Runtime Error:
/box/script.js:2
console.log(myNum.split(""));
^
TypeError: myNum.split is not a function
Explanation:
In the preceding illustration, a variable called myNum has been defined utilizing the let keyword, and it has been initialized with the value 30. In this instance, we attempted to execute a string method on a numerical value by using console.log(myNum.split("")). This action resulted in a TypeError.
- URIError: This error type arises when inappropriate arguments are supplied to the functions encodeURI or decodeURI.
Example:
To illustrate this concept, let's consider an example.
Example
console.log(decodeURI("https://logic-practice.com/"))
console.log(decodeURI("%Example"));
Output:
https://logic-practice.com/
Runtime Error:
/box/script.js:2
console.log(decodeURI("%Example"));
^
URIError: URI malformed
Explanation:
In the preceding illustration, we utilized decodeURI to interpret a valid URI string. Initially, we displayed the original URI in the console, and subsequently, we provided an incorrectly encoded string %Example, which results in a URIError since %t is not recognized as a valid URI escape sequence.
- Custom Errors: A custom error refers to an error type defined by the developer, aimed at delivering messages that are relevant and comprehensible for our application. It clarifies precisely what the issue is in a manner that is straightforward to grasp and rectify.
Example:
Let's have an example of it.
Example
throw new Error("Custom error happened");
Output:
Runtime Error:
/box/script.js:1
throw new Error("Custom error happened");
^
Error: Custom error happened
Clarification: In the code presented above, a custom error has been generated. A message has been conveyed to the user via this error.
Exception Handling Statements
The following statements handle any exception that occurs:
- throw statements
- try…catch statements
- try…catch…finally statements.
We will see each of them with an example:
throw Statements:
Utilizing the throw statement allows us to generate a custom error.
Example:
To illustrate the use of the throw statement, let’s consider an example:
Example
function verifyAge(age) {
if (age < 18) {
throw new Error("Age must be 18 or above");
}
console.log("Access granted");
}
try {
verifyAge (16);
} catch (error) {
console.error(error.message);
}
Output:
Runtime Error:
Age must be 18 or above
Explanation:
In the preceding example, we defined a function called verifyAge. This function, verifyAge, checks if the age provided is less than 18. If the age is indeed less than 18, an error is generated, and the message "Age must be 18 or above" is presented to the user. The verifyAge function is invoked within the try block, with the argument 16 being passed to it. It evaluates whether 16 is less than 18. Consequently, an error is produced.
try…catch statements:
Within the try…catch construct, the subsequent actions take place:
- Try Block: This segment encompasses code that has the potential to generate an error.
- Catch Block: This section includes the code that runs in the event of an error occurring within the try block.
Syntax:
try{
// Code that may throw an error
} catch(error) {
// Code to handle the error
}
Example:
Let's have an example of try…catch statement.
Example
try {
let res = 10 / 0;
if(!isFinite(res)) {
throw new Error("Cannot divide by zero");
}
console.log(res);
} catch (error) {
console.error("Error occurred:", error.message);
} finally {
console.log("Execution completed");
}
Output:
Execution completed
Runtime Error:
Error occurred: Cannot divide by zero
Explanation:
In the preceding example, the try block attempts to divide 10 by 0. The resulting output will be Infinity. Subsequently, it checks if the outcome is a finite value by employing the isFinite function. In this instance, the division yields Infinity; the catch block captures the generated error and outputs the message "Error occurred: Cannot divide by zero" to the console.
try…catch…finally statements:
The try…catch…finally statement is the same as Try…catch but we add a finally block which runs every time.
- Try Block: Try block contains the code that may throw an error.
- Catch Block: It contains the code that executes when there is any error in the try block.
- Finally Block: This block contains the code that always executes, whether an error occurred or not.
Syntax:
try{
// Code that may throw an error
} catch(error) {
// Code to handle the error
} finally {
// It is optional. It runs whether the code is successful or has an error.
Example:
Let's have an example of try…catch…finally.
Example
try {
let res = 10 / 0;
if (!isFinite(res)) {
throw new Error("Cannot divide by zero");
}
console.log(res);
} catch (error) {
console.error("Error occurred:", error.message);
} finally {
console.log("Execution completed");
}
Output:
Execution completed
Runtime Error:
Error occurred: Cannot divide by zero
Explanation:
In the previous illustration, we addressed the error by utilizing a try-catch block. In this case, we attempt to divide 10 by 0 and subsequently verify if the outcome is finite through the use of isFinite. If the result is not finite, an error is thrown with the message "Error occurred: Cannot be divided by zero."
Exception Propagation in JavaScript Async/Await:
When a programmer composes asynchronous code in JavaScript, it is crucial for them to comprehend the mechanics of exception propagation within the language. In JavaScript's asynchronous functions, any error that occurs will be passed along to the corresponding await statement. This design simplifies the process of managing exceptions significantly.
Example
async function fetchData() {
try {
let res = await fetch("https://api.logic-practice.com/data");
let d = await res.json();
console.log(d);
} catch (error) {
console.error("Error fetching data:", error.message);
}
}
fetchData();
Output:
Runtime Error:
Error fetching data: fetch is not defined
Explanation:
In the preceding example, we managed the error through the use of a try..catch structure. We established an asynchronous function called fetchData, within which we implemented a try-catch block. Within the try segment, we attempted to retrieve the API data using the fetch method. Conversely, in the catch segment, we provide a notification in the event that the API retrieval encounters a failure. In this instance, it raises an error and presents the message "Error fetching data: fetch is not defined."
Advantages of Exception Handling:
The advantages of exception handling are as follows:
- Gracefully Handles: It handles the error gracefully. If any error occurs, then the code keeps running smoothly.
- Error Logging: It is helpful as it logs the details of the error which can help you locate and fix the issues.
- Prevents Crashes: It prevents an application from crashing when it cannot process some data.
- Enhanced Program Robustness and Stability: Exception handling prevents errors and handles them which makes the application more resilient to unexpected situations. It makes programs more robust and stable.
- Better User Experience: When we use exception handling, we can display a meaningful message to the user instead of abrupt crashes or cryptic error messages. It helps users to understand the issue.
Best Practices for Exception Handling in JavaScript:
Here are some of the best practices for using exception handling in JavaScript:
- Always have only the piece of code that will throw an exception inside the try block. Prevent having irrelevant code inside the try block.
- We should use logging for exceptions to ensure that we capture sufficient details for debugging.
- It creates custom error classes to represent specific error conditions. This helps us to debug more easily by providing clear error types.
- The finally block always runs after the try or catch block. We should utilize it for resource clean up. For example, closing files and clearing timeouts.
Global Error Handling:
While developing a web-based JavaScript application, we may encounter unforeseen errors in our code, despite our diligent efforts to address all potential exceptions. To mitigate the occurrence of these kinds of exceptions, it is advisable to implement a global error-handling strategy.
We can implement this by using the window.onerror event listener. This approach is effective for intercepting all uncaught errors that occur within the browser. It offers a mechanism to either log these errors or react to them in a meaningful manner.
window.onerror = function (message, source, lineno, colno, error) {
console.log('An error occurred:', message, 'at line:', lineno, 'in file:', source);
// Prevent the default handling of the error
return true;
};
By returning true, you inhibit the default error logging behavior of the browser. Should you wish to log errors while still being able to view them in the console, you can either return false or simply eliminate the return statement altogether.
Conclusion:
Exception management plays a crucial role in error handling. It allows us to avoid having our application show unanticipated errors. Developers are encouraged to implement exception handling in their applications. This article addresses all significant aspects of exception handling. By employing exception management, we can create resilient code that can be easily debugged and corrected.
- In JavaScript, what is exception handling and why is it important?
In JavaScript, handling exceptions refers to the process of managing unexpected events that occur during the execution of a program. This mechanism allows developers to gracefully manage errors, which is crucial for stopping applications from crashing. It ensures that the code execution proceeds smoothly even in the presence of issues.
- What is the method for managing multiple exceptions within a single catch block?
The || (or) operator can be employed to manage several exceptions simultaneously. It is possible to address various categories of exceptions within a single catch block. Additionally, the instanceof operator can be used inside the catch block to verify the type of the error and respond appropriately.
- What is the functionality of the throw statement in JavaScript?
In JavaScript, the throw statement is employed to generate an exception. While it is possible to throw any type of value, it is advisable to throw objects that are derived from the built-in Error object. This approach offers valuable details regarding the encountered error.
- In JavaScript, how do a syntax error and a logical error differ?
When the code violates any JavaScript syntax rules, it results in a syntax error. This type of error stops the code from running altogether. In contrast, a logical error happens when the code executes without any issues but produces results that are not as expected.
- What methods can I use to manage runtime errors in JavaScript?
A runtime error can be managed using try, catch, and finally blocks. The catch block enables us to capture the error and present a custom error message to the user without halting the execution of the program.