Per this fiddle, if I try to call a second promise function from the .finally() block of the first promise, the second promise resolves but the resolve value is "undefined".
However, if I call the second promise function in a .then block after the .finally block, everything works as expected. Why can’t I call the second promise in the .finally block of the first promise?
Example that fails (Promise 2 value is "undefined"): https://jsfiddle.net/scemohkb/
function res(v) { return new Promise((resolve, reject) => { resolve(v); }) }
function rej(v) { return new Promise((resolve, reject) => { reject(v); }) }
rej(1)
.then((val) => {
console.log(`Value1: ${val}`);
})
.catch((e) => {
console.error(`Caught 1: ${e}`);
})
.finally(() => {
console.log("Finally 1");
return res(2);
})
.then((v) => {
console.log(`Value2: ${v}`); // THIS DOESN'T WORK: v is undefined
})
.catch((e) => {
console.log(`Caught 2: ${e}`);
})
.finally(() => {
console.log("Finally 2");
});
Example that works: (Promise 2 returns the correct value): https://jsfiddle.net/scemohkb/1/
function res(v) { return new Promise((resolve, reject) => { resolve(v); }) }
function rej(v) { return new Promise((resolve, reject) => { reject(v); }) }
rej(1)
.then((val) => {
console.log(`Value1: ${val}`);
})
.catch((e) => {
console.error(`Caught 1: ${e}`);
})
.finally(() => {
console.log("Finally 1");
})
.then(() => {
return res(2);
})
.then((v) => {
console.log(`Value2: ${v}`); // This works: v is the correct value.
})
.catch((e) => {
console.log(`Caught 2: ${e}`);
})
.finally(() => {
console.log("Finally 2");
});
In example 1, the second promise function still returns correctly upon calling resolve() and the .then block is executed, but the value sent to resolve() is ignored and instead the .then() function receives "undefined".
What is different about the .finally() function that I’m missing, that prevents this from happening? It would seem to make sense for the cleanest chaining of multiple promises that can resolve or reject independently, vs. adding another .then() function after the .finally().
2
Answers
Directly copy pasting from the docs:
A finally() call is usually transparent and does not change the eventual state of the original promise. So for example:
Unlike Promise.resolve(2).then(() => 77, () => {}), which returns a promise eventually fulfilled with the value 77, Promise.resolve(2).finally(() => 77) returns a promise eventually fulfilled with the value 2.
Similarly, unlike Promise.reject(3).then(() => {}, () => 88), which returns a promise eventually fulfilled with the value 88, Promise.reject(3).finally(() => 88) returns a promise eventually rejected with the reason 3.
The only exception to the above rule is when
finally()
itself rejects (by throwing a value)..finally()
resolves with the value that the.then()
and.catch()
resolve with. The main reason this does not work is there is no return from inside the handlers of fromthen()
andcatch()
and hence no resolution/rejection. That is whyfinally()
also does not resolve/reject with any value.If you return a value from inside the handlers of
then()
andcatch()
, then the handler offinally()
can resolve/reject with that value.Uncomment the above code to play around with it:
Reading: This is what the docs mention about return values from inside the handler function of
then()
:The
finally()
function return value is ignored unless it is a rejected promise:If you want to handle the
res(2)
Promise
with those functions, you have to do so withinfinally
:That will result in the output: