finally
Back to the chain of tasks. The intern takes a calculator from the desk and puts it back when done. But if the work fell through and he threw a note with the reason up the chain, he may forget the calculator. The next intern will come and not find it.
In a program this happens to variables that code changes for the time of its work. When an error is thrown in a try block, the lines after it do not run. If one of them was important, it is lost too. The function load parses JSON text and for that time sets a flag — the variable loading with the value true:
let loading = false;
function load(text) {
loading = true;
const data = JSON.parse(text);
loading = false;
return data;
}
try {
load("{ bad");
} catch (e) {
console.log("caught"); // caught
}
console.log(loading); // trueLet's see what happened:
loadsetloadingtotrue.JSON.parsethrew aSyntaxErroron the wrong text.- The function stopped before the line
loading = false. - The
catchoutside caught the error and printedcaught. - The flag stayed
true: the program thinks loading is still going on.
The finally block
After try and catch you can add a finally block. This is "putting the calculator back": the block runs whatever the outcome. There are three outcomes:
tryfinished without errors;catchcaught an error;- the error left the function.
So finally holds what must happen in any case. If catch runs, finally runs after it.
Most often finally undoes what the code did for the time of its work: it clears a flag or gives a counter back its old value.
function load(text) {
loading = true;
try {
return JSON.parse(text);
} finally {
loading = false;
}
}Let's see what changed:
loading = truestill comes first in the function.- Parsing the text moved into
try, and clearing the flag intofinally. - There is no
catchblock here: the calling code catches the error fromJSON.parse, as in the first example. - Before the error leaves the function,
finallyclears the flag, andconsole.log(loading)printsfalse.
A try with finally and no catch is allowed, while a try with neither catch nor finally is not.
finally and return
finally is not skipped even when try ends with a return. The function remembers the value to return, then runs finally, and only after that does the calling code get the value:
function count() {
try {
console.log("try"); // try
return 1;
} finally {
console.log("finally"); // finally
}
}
console.log(count()); // 1Let's look at the order of the lines:
tryprintstry.return 1remembers the result, but the function has not finished yet.finallyprintsfinally.- Only now does the outer
console.logget1and print it last.
Interviewers often check this order: "Does finally run if try has a return?" It does, and before the calling code gets the value.
Here the intern picture stops working: a person can forget the calculator, but finally never forgets. Even a return in try does not cancel it.
Common mistake
A return is written in finally:
function load(text) {
try {
return JSON.parse(text);
} finally {
return null; // ✗
}
}There is no error message, but the function is broken. A return in finally replaces the value from try, so load('{"a":1}') returns null. It cancels a thrown error as well: for "{ bad" the function quietly returns null, and the catch outside gets nothing. Keep only actions such as loading = false in finally, with no return.
Key points
finallyruns whatever the outcome: with no error, aftercatch, and when the error leaves the function.finallyputs back what the code changed for the time of its work, such as clearing a flag.- After a
returnintry, thefinallyblock runs before the calling code gets the value. - A
returninfinallyreplaces the result and cancels a thrown error, so it is not written there.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.