Home > Software design >  Exception handling in promise chain
Exception handling in promise chain

Time:10-13

I have a code with multiple promise chain as shown below

.then(function(response) {
    //my code   
})
.then(function(app) {
    //my code
})
.then(function() {
    //my code   
})

Have added exception handling to each of them as shown below so that if one breaks the rest chain continues.

Is this the correct way of handling exception for multiple chain blocks, or any best practice can be followed to handle the exceptions so that the code execution doesn't break if one fails.

.then(function(response) {
    //my code   
})
.catch(e => {})

.then(function(app) {
    //my code
})
.catch(e => {})

.then(function() {
    //my code   
})
.catch(e => {})

CodePudding user response:

If your code can accommodate the error (whatever it is) that's occurring early on, this can be a reasonable way of doing it, but I'd always have to look twice at it in a code review because it's fairly unusual for the code to be able to just ignore errors like that. The code is roughly equivalent to:

try {
    //my code   
} catch (e) {
}

try {
    //my code
} catch(e) {
}

try {
    //my code   
} catch(e) {
}

...but using promises instead. So it's a bit suspect, but can be correct, for the same reasons the above is a bit suspect but can be correct if you need to do a series of things, one at a time, and have each of them done even if the previous one fails.

Beware that it means app in the subsequent fulfillment handler will be undefined:

.then(function(response) {
    //my code   
})
.catch(e => {})

.then(function(app) { // <=== `app` is `undefined` here
    //my code
})
.catch(e => {})

.then(function() {
    //my code   
})
.catch(e => {})

CodePudding user response:

Answer posted before, is correct.

I just want to insert my 2 cents.

You can have some fun with one helper function (or use something more fancy like whole Either monad thingy from fp-ts package)

const run = async (fn) => {
    try {
       const result = await fn()
       return [result, null]
    } catch (err) {
        return [null, err]
    }
}

and write code without try\catch or .then\.catch

const [response, error] = await run(() => fetch('asdfasdf'))
const app = buildApp(response.ok ? await response.json() : { fallback: 'data' })

const [appResponse, appError] = await run(async () => {
  await app.compileTemplate()
  return app.buildResponse()
})

if (appResponse) {
 // ...
}

Or more useless approach, you can throw a custom error, so your first .catch block will be able to do something.

class AppFromResponseError extends Error {
  constructor(message, fallbackApp) {
    super(message)
    this.name = "ResponseError"
    this.app = "fallbackApp"
  }
}

builder
  .then(function(response) {
    if (response.ok !== true) 
      throw new AppFromResponseError('not ok', minimalApp)
  })
  .catch(e => {
    if (e.app) return e.app
  })
  .then(app => { /* some kind of app will be here */})
  • Related