.finally understanding the promise chain
The value of Promises in Javascript cannot be overstated. They are used everywhere, helping to navigate the asynchronous maze that comes with frontend development. There is an intimate familiarity with .then
and .catch
, allowing the handling of whether asynchronous actions were successful or not.
But if .then
runs once upon the resolution of a promise and .catch
runs on the rejection of a promise, when exactly does .finally
run? .finally
runs after a promise is settled, regardless of whether it was resolved or rejected - this means that .finally
runs after either the .then
or the .catch
.
This sounds obvious, but what does it actually mean? Let’s look at a few examples - although for the sake of clarity I will be using Promise.resolve()
, it applies to any promise that you may have there.
If the following code block were to execute…
Promise.resolve()
.finally(() => {
return 'Finally!';
})
…what value would be returned? You might think that we would get back 'Finally!'
, but in this case, we would actually get back undefined
.
Let’s dive into this a little bit deeper. The promise runs, and it either resolves or rejects (in the case of the code above, it resolves). If it resolves or rejects, a .then
or .catch
will trigger respectively if provided. At this point, the promise is considered settled, and then our .finally
will trigger. However, as the promise is already settled by the time the .finally
triggers to run, it is impossible to return
a value from it.
Let’s look at another example:
let response = null;
Promise.resolve()
.then(() => {
response = 'Resolved!';
Promise.resolve()
.then(() => {
response = 'x2!';
})
})
.finally(() => {
response = 'Finally!';
})
In the example above, we are setting response
with a different string value based on where we are in the execution of the code. We also have a second promise nested within the .then
.
We would expect response
to first be null
. Once the promise resolves, it would set to Resolved!
as the .then
triggers, both setting the response value and calling another promise.
This is where it gets a little tricky. We actually end up with a race condition. In the case of our explicit Promise.resolve()
, it resolves before the promise is finished settling, and so we end up setting the value to x2!
and then the promise settles, the .finally
triggers, and we get Finally!
. While this scenario is unlikely in practice as asynchronous calls do not resolve quite that quickly, it is still good to be aware of.
If this were a true asynchronous call happening, we would instead have the .finally
trigger, setting the value to Finally!
, and then our second promise would resolve, setting our variable to its final value of x2!
.
In summary, asynchronous code always adds complication into development, and it’s important to be able to accurately track what code is running in what order so that you can properly anticipate the state of your application. Hopefully this was helpful in giving an idea of when .finally
runs on our promises!