This article is going to take you into the world of the “finally”. We will take a look at how to handle the try/catch/finally blocks, but we will also learn more about the Promise and a finally() method.
1. What you should know about the try/catch/finally blocks?
We’ve already taken a peek at one of the most recognized exception handling mechanisms – the try/catch/finally statement, but let’s summarize the main points again:
- when an exception occurs in the try block, block of statements from a catch clause is invoked
- the finally block follows the catch clause – the finally block consists of a cleanup code and this code is definitely executed, regardless of whether or not the error is thrown and no matter what happens in the initial try block.
- the try block is obligatory but must be followed by at least one of the optional – catch or/and finally – blocks
- after the try block and catch block execute, the finally block will execute if it’s provided
When we are using the blocks, we must understand the follow-up of the return values. Let’s take a look at one example of the try/catch/finally blocks in the function, where we expect a user to insert a number that is higher than 3, but lower than 6.
We’ve prepared several scenarios with if conditionals:
- the system accepts the number if the values is is higher than 3, but lower than 6
- the system throws an error if there is no value and returns “please insert some value”
- the system throws an error if a value is not a number and returns “value is not a number”
- the system throws an error if a value is higher than 6 and returns “value is too high”
- the system throws an error if a value is lower than 3 and returns “value is too low”
When you’re using the try/catch/finally blocks, you should be aware of which block’s return values will be returned.
Let’s take a look at the code, where the finally statement will help you execute the code after the try and catch, no matter what the result is:
<html>
<body>
<p>Please insert a number between 3 and 6:</p>
<input id="demo" type="text">
<button type="button" onclick="testValue()">Test your value</button>
<p id="myMessage"></p>
<script>
function testValue() {
var myMessage, a;
myMessage = document.getElementById("myMessage");
myMessage.innerHTML = "";
a = document.getElementById("demo").value;
try {
if(a == "") throw "please insert some value";
if(isNaN(a)) throw "value is not a number";
if(a > 6) throw "value is too high";
if(a < 3) throw "value is too low";
}
catch(err) {
myMessage.innerHTML = "Input " + err;
}
finally {
document.getElementById("demo").value = "";
}
}
</script>
</body>
</html>
1. What you should know about the Promise and a finally() method
First, let’s recap what a Promise in Javascript is. A Promise is an object used as a proxy for a value that is not known at the moment. Maybe this is the very reason, it is called a Promise – the value is not yet known, but JavaScript PROMISES to return that value at some point. So, for example a synchronous method (such as try/catch/finally statement is) would immediatelly return the final value, but a Promise allows you to use an asynchronous method. That means that you would wait for the final value to be returned, and afterwards you would do the next things you planned to do when that final value is returned. This is done is the form of .then() methods, which is a common practice to learn if you’re working with Promises. .then() is sort of attaching a callback functions onto Promise so it can handle what comes back from it – .then() takes a callback function and returns another Promise.
Some of the built-in Promise-specific methods are .catch() and .finally(). Here, we are going to focus on finally() method, which was introduced in ES2018 and represents a method that is always executed regardless a promise was fulfilled or rejected, so basically when the promise is settled. With a finally() method you can add a code that cleans the resource when the promise is settled, which enables you to bypass duplicate code in the then() and catch() methods.
It the example below we’re duplicating the code in the then() and catch() methods:
promise
.then(result => {
// system processes the result
// system cleans the resources
})
.catch(error => {
// system handles the error
// system cleans the resources
});
But as said above the finally() method helps you avoid duplicating the code because you can put the entire code that cleans the resources in the finally method. Therefore, the finally() method can be useful if you want to do some processing or cleanup once the promise is settled, whatever the outcome is – either the promise is resolved or rejected.
promise
.then(result => {
// system processes the result
})
.catch(error => {
// system handles the error
})
.finally(() => {
// system cleans the resources
});
In terms of avoiding duplicate code and cleaning it, we can try to compare the finally() method to the finally block that is covered in the try/catch/finally statement that we’ve covered above. The finally() method is used in asynchronous code, while the finally block from the try/catch/finally statement is used in the synchronous code to clean up the resources.
So, what happens in the above code? The Promise executes immediately – it either resolves to a single value, or rejects with an error object. So, when the system rejects the Promise, the return value passes through .then()s and then the .catch() picks it up. But, once a promise has been settled – either rejected or resolved – it cannot be settled again. The job can be either: finished with success and results in a value, which means the job is resolved, or another option is, rejection, which means an error has occurred and that error is the error object.
As the MDN says: “Promise.prototype.finally() – The finally() method returns a Promise. When the promise is settled, i.e either fulfilled or rejected, the specified callback function is executed. This provides a way for code to be run whether the promise was fulfilled successfully or rejected once the Promise has been dealt with. This helps to avoid duplicating code in both the promise’s then() and catch() handlers.”
function checkPassword(password) {
return new Promise((resolve, reject) => {
if (password === "secret") {
resolve("Password is correct.");
} else {
reject(new Error("Password is not correct"));
}
});
}
checkPassword("secret")
.then((msg) => {
console.log(msg);
})
.catch((err) => {
console.error(err);
})
.finally(() => {
console.log("You completed a test");
});
We’ve created a function called checkPassword(), which does what it says – it checks whether your password is correct. We defined the password with if conditional to be strictly equal to “secret”. Within this function, we want to have a return of a new Promise – either the Promise is resolved or rejected – either your password is correct or not. If your password is correct (password === secret) we have a resolution of a Promise with a message “Password is correct”, and if your password isn’t correct, we get an error, or in Promise’s terminology, we have a rejection that console logs “Password is not correct”. Through a function call (with a help of .then), a Promise results in console.log(msg) or catches (.catch) an error and messages “Password is not correct”. Nevertheless, at the very end, either the Promise is rejected or resolved, we get a definite .finally(), which results in a console.log “You completed a test”.
It is also important to bring out that the finally() method is very similar to calling .then(onFinally, onFinally) however there are a few differences:
- when you create a function inline, you can pass it once, which means you don’t have to declare it two times, or even create a variable for it
- sometimes you simply don’t need rejection or resolution reason – a finally callback does exactly that – it does not receive any argument, in terms of whether a Promise was rejected or resolved.