Reputation: 698
Here is JS code:
function createPromise() {
const result = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('my error'));
}, 2000);
});
// uncomment this to get error
// result.finally(() => {
// console.log('finally before');
// });
return result;
}
function test() {
createPromise()
.then(() => {
console.log('promise then');
})
.catch((error) => {
console.log('promise catch:', error);
})
.finally(() => {
console.log('promise finally');
});
}
Its works properly and after executing I have in the console:
promise catch: Error: my error
promise finall
But after uncommenting:
result.finally(() => {
console.log('finally before');
});
In console I have uncaught exception:
finally before
promise catch: Error: my error
promise finally
Uncaught (in promise) Error: my error
Why is this happening and how to explain it?
Upvotes: 4
Views: 1306
Reputation: 19311
The unhandled promise
Like .then
and .catch
, .finally
returns a promise. But unlike .catch
or .then
with a second argument supplying an onrejection
handler, finally
does not fulfill the promise it returns if the previous promise in the chain becomes rejected.
So the expected output without the comments for the result
promise is the same. But in addition there is the promise returned by .finally
in createPromise
that doesn't have a rejection handler. Hence the uncaught promise rejection error.
The .finally
in function test
is okay because the preceding catch clause fulfills the promise it returned so .finally
won't reject the promise it returned.
More about the finally
method of a promise
Generally a .finally
clause passes through the result, or promise rejection reason, of the previous promise in a promise chain to the next promise in the chain.
However, if finally
handler code throws an error or returns a rejected promise when called, the next promise in the chain is rejected for the same error or rejection reason - any data or rejection reason arriving from previous promises in the chain is effectively discarded.
How to stop finally
handler code generating uncaught rejection errors.
Return the chain formed by calling finally
on the new Promise:
function createPromise() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('my error'));
}, 2000);
})
.finally( () => {
console.log('finally before');
});
}
If the finally
handler throws or returns a rejected promise, such thrown value or rejection reason rejects the promise synchronously returned when finally
was called, leaving it to the caller of createPromise
to handle.
A second method to suppress uncaught rejection reasons is to add a dummy catch
handler, although this is rarely used and not recommended in most cases.
result.finally(() => {
console.log('finally before');
})
.catch( err => err); // avoid unhandled rejection
would handle promise rejection originating from within the finally
handler (or promise rejection of result
) by having catch
return a fulfilled promise that is never used.
Upvotes: 4