1

I am having chained promises handled by one catch block.

If one of the promises rejects, I want to do the clean up in the catch block depending on which step failed.

However, the cleanup itself also returns a Promise which needs to fulfill before I can finally reject the function.

The issue is: What if my cleanup promise does not resolve? Wouldn‘t this cause a loop of .then & .catch? How can I make sure that my cleanup executes before ending the function?

Example:

return promise1() .then(() => promise2) .then(() => promise3) .then(() => { return { result: xyz } } .catch((error) => { return cleanup() .then(() => { throw(error) } } 
2
  • 2
    There’s no loop. You should make a cleanup function that rejects and play around with it. Commented Jan 5, 2022 at 23:27
  • Could you just add another .catch to the chain on cleanup? Commented Jan 5, 2022 at 23:56

3 Answers 3

2

Personally, I would just use async / await syntax. This allows for simpler control of waits and resolve / reject values.

const myAsyncFun = async () => { try { await promise1() await promise2 await promise3 return { result: "xyz" } } catch (error) { try { await cleanup() } catch (cleanupError) { // handle cleanup error } finally { throw error // reject with the original error } } } 

Original answer below...


Sounds like you want to use Promise.prototype.finally()

When the promise is settled, i.e either fulfilled or rejected, the specified callback function is executed

.catch(error => cleanup() .catch(cleanupErr => { // handle cleanup error here }) .finally(() => Promise.reject(error)) ) 

This will ensure that the result is a rejected promise (rejecting with error) whether cleanup() resolves or not.


Demo

const cleanup = (fail) => !fail ? Promise.resolve("cleanup good") : Promise.reject("cleanup bad") const go = (failMain, failCleanup) => { const p = !failMain ? Promise.resolve("main good") : Promise.reject("main bad") return p.then(() => ({ result: "xyz" })) .catch(error => cleanup(failCleanup) .catch(cleanupErr => { // handle cleanup error here console.warn(cleanupErr) }) .finally(() => Promise.reject(error)) ) } (async () => { console.info("No errors") await go(false, false).then(console.log, console.error) console.info("Main error only") await go(true, false).then(console.log, console.error) console.info("Main and cleanup errors") await go(true, true).then(console.log, console.error) })()

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! I am wondering what I should do if the cleanup rejects since the cleanup might be critical for the app state. Any idea on how to “ensure” or deal with it?
@ktm125 I've added some more info and a demo
1

To your first question: No! Once your program is in the catch block, it has nothing to do with the promises in it, so it will not catch cleanup().

To your second question: You can of course write another catch block for it and throw an error with a relevant error message (For instance "Cleanup could not be executed")

2 Comments

The problem is that if cleanup() fails, the final result will be the cleanup rejection value and not the original error
That problem can also be solved by throwing it anyways in the catch block of the cleanup() function.
0

You're good to go.

Your current code will await the cleanup function properly, because returning a promise from a chaining callback (then, catch, finally) makes both resolution and rejection propagate correctly.

Even if the cleanup function failed, it wouldn't cause any problems; the rejection would propagate to the outermost (returned) promise, and the caller code could catch it the same way as a failure from the promise1, promise2 or promise3 functions.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.