Promise Cleanup with .finally()

Promise.finally() is the try...catch...finally for async code, guaranteeing logic runs after a promise settles. Use it to hide a loading spinner or close a network connection without duplicating code in .then() and .catch().
Why it exists
Before .finally(), developers had to place the same cleanup code in both the .then() block for success and the .catch() block for failure. This was repetitive and error-prone. .finally() provides a single, guaranteed place for code that must run regardless of the promise's outcome, simplifying logic.
The mental model
Think of .finally() as the janitor for your asynchronous operations. After the main event is over, whether it was a success or a failure, the janitor comes in to clean up—turning off the lights, closing a connection, or hiding a spinner. The janitor doesn't care about what happened, only that it's over and it's time to reset the state.
How it works
When you chain .finally(onFinally) to a promise, the onFinally function is scheduled to execute when the promise settles. The onFinally callback receives no arguments. The .finally() method itself returns a new promise that passes through the original promise's result. For example, Promise.resolve(42).finally(() => {}) will still resolve with 42. The only exception is if onFinally throws an error or returns a rejected promise; in that case, the entire chain will reject with that new error.
When to use it
Use .finally() for any action that needs to happen after an async operation completes, regardless of success or failure. Common use cases include: hiding a loading spinner, closing a file handle or database connection, or logging the completion of an operation for analytics. It keeps your .then() and .catch() blocks focused purely on handling success and failure data.
When not to use it
Do not use .finally() if you need to transform a resolved value or handle a specific error. That is the job of .then() and .catch(). Because the finally callback receives no arguments and its return value is ignored (unless it's an error), it is purely for side-effects and cleanup, not for data manipulation.
One canonical example
Imagine fetching data while showing a loading spinner. You must hide the spinner whether the fetch succeeds or fails.
showSpinner();
fetchData()
.then(data => displayData(data))
.catch(error => displayError(error))
.finally(() => hideSpinner());Here, hideSpinner() is guaranteed to run, preventing the spinner from getting stuck on the screen.
Interview question
Which statement best describes the unique characteristic of Promise.finally()?
- a.It allows modifying the resolved value or error before passing it down the chain.
- b.It executes a callback function only if the promise rejects, providing a last chance for error handling.
- c.It guarantees a callback runs after the promise settles, without receiving any arguments or altering the promise's outcome.Correct
- d.It provides a way to retry a failed promise a specified number of times before finally rejecting.
Why? this is the answer
Promise.finally() is designed for cleanup, ensuring a callback runs after a promise settles (either resolves or rejects) without receiving any arguments or affecting the promise's final value or error. Option A is incorrect because .finally() does not modify the promise's value or error; that is the function of .then() and .catch().
Just read this? Test yourself on what you have been reading.
Read the original → developer.mozilla.org
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on javascript — each one lists the topics its interview covers.
See open roles