最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Return success when handling error in a promise - Stack Overflow

programmeradmin3浏览0评论

I have a promise that handles a HTTP request performed over a Web API:

promise = promise.then(r => { 
    // ...
  }, error => {
    if (error.status == 404) {
      // Here I can fix an error and continue properly
    } else {
      // Here the error should be propagated further in the promise
    }
}

// later in the code:
promise.catch(r => { /* More error handling */ } );

Later in the code this promise is chained to more error checks.

In case of a 404 error, I can actually "fix" a problem, and I don't want the other handler to trigger. I'd rather want to make the promise a success in this case. How can I do that?


A bit more code to explain my case more deeply:

refresh() {
  this.refreshAsync().catch(r => {
     // Show error to the user.
     notifications.showError("Unexpected error happened");
  });
}

async refreshAsync() {
  // Here goes a lot of vue-resource calls to gather the necessary data for a view. They are chained with `await`. Only one of them:
  await this.$http.get(url).then(r => {
    this.data = r.data;
  }, error => {
    // 404 is actually a legit response for API to return, so the user notification above should not be shown
    if (error.status == 404) {
      // handle successfully
    } else {
      // propagate an error, so the handler above could show a warning to the user.
    }

  });

}

I have a promise that handles a HTTP request performed over a Web API:

promise = promise.then(r => { 
    // ...
  }, error => {
    if (error.status == 404) {
      // Here I can fix an error and continue properly
    } else {
      // Here the error should be propagated further in the promise
    }
}

// later in the code:
promise.catch(r => { /* More error handling */ } );

Later in the code this promise is chained to more error checks.

In case of a 404 error, I can actually "fix" a problem, and I don't want the other handler to trigger. I'd rather want to make the promise a success in this case. How can I do that?


A bit more code to explain my case more deeply:

refresh() {
  this.refreshAsync().catch(r => {
     // Show error to the user.
     notifications.showError("Unexpected error happened");
  });
}

async refreshAsync() {
  // Here goes a lot of vue-resource calls to gather the necessary data for a view. They are chained with `await`. Only one of them:
  await this.$http.get(url).then(r => {
    this.data = r.data;
  }, error => {
    // 404 is actually a legit response for API to return, so the user notification above should not be shown
    if (error.status == 404) {
      // handle successfully
    } else {
      // propagate an error, so the handler above could show a warning to the user.
    }

  });

}
Share Improve this question edited Oct 16, 2018 at 8:42 Archeg asked Oct 16, 2018 at 8:27 ArchegArcheg 8,4628 gold badges51 silver badges95 bronze badges 5
  • How is your promise declared ? You'll have to detect the 404 error and call reject(). – Zenoo Commented Oct 16, 2018 at 8:29
  • can you show us how do you intend to handle the success case? – Aseem Upadhyay Commented Oct 16, 2018 at 8:29
  • @Zenoo This is a promise returned by vue-resource. I'm not in control of declaration – Archeg Commented Oct 16, 2018 at 8:31
  • @AseemUpadhyay please see the update – Archeg Commented Oct 16, 2018 at 8:38
  • Have you tried using interceptor? – barbsan Commented Oct 16, 2018 at 8:55
Add a ment  | 

3 Answers 3

Reset to default 3

You can simply return a reject/resolve

if(error.status == 404)
    return Promise.resolve('OK')
else
    return Promise.reject('fail')

I made an example showing how this work, just for this case:

httpRequest = function () {
  return new Promise(function (res, rej) {
    let status = (Math.round(Math.random()) === 1) ? 200 : 404;
    console.log(status)
    if (status === 200)
        return res({ status })
    else
        return rej({ status })
  })
}

let promise =
httpRequest()
    .then(res => Promise.resolve('success'))
    .catch(e => {
        if (e.status === 404)
            return Promise.resolve('success')
        else
            return Promise.reject('failed')
    })

promise
.then(res => {
    console.log(res)
})
.catch(e => {
    console.log('this should not happen')
})

If you need to propagate your success flow when you "fix" it, I can think of two approaches here,

  1. You can wrap your further propagation logic in a function and then call it in the error scenario.
  2. Wrap your promise in another promise and call resolve(yourValue) on error 404. But then this will mean you'll have to change your further chained logics on the promise object, but on the contrary this will give you more flexibility.

Hope it helps ;)

EDIT

After seeing your code, I still feel it is achievable by what I have mentioned before. You can do something on the lines of -

refreshAsync = async () => {
   return new Promise((resolve,reject)=>{
       await this.$http.get(url).then(r => {
           this.data = r.data;
        }, error => {
            if (error.status == 404) {
                 resolve(); //populate this with your desired value
           } else {
                 reject();
           }
   })
}

If you're using the standard Promise implementation, you can simply just throw an error and then it will be returned as a failed promise result to the next catch method:

// let's assume we have the following async operation
const somePromiseCall = () =>
  new Promise(resolve => setTimeout(() => resolve(), 1000))

somePromiseCall()
  .then(() => {
    if (Math.random() > .5) {
      throw 'this is the error message'
    }

    return 'this is the result'
  })
  .then(result => console.log('success', result))
  .catch(err => console.error('fail', err))

Another way to do this is just by returning another promise that you can immediately reject (either by returning new Promise((resolve, reject)=>reject('error message')) or by returning the shorthand method Promise.reject('error message'):

// let's assume we have the following async operation
const somePromiseCall = () =>
  new Promise(resolve => setTimeout(() => resolve(), 1000))

somePromiseCall()
  .then(() => {
    if (Math.random() > .5) {
      return Promise.reject('error message')
    }

    return 'this is the result'
  })
  .then(result => console.log('success', result))
  .catch(err => console.error('fail', err))

The reason why the second version works is because any return value from a then or catch method is wrapped in a promise and passed on so you can chain then calls. Knowing this, if you return a value, the then method, behind the scenes, actually returns something like Promise.resolve(returnValue), so that you can do chaining:

somePromiseCall()
  .then(result => result + 1)
  .then(newResult => /* newResult === result + 1 */) 

That's why the above snippet is similar to this one:

somePromiseCall()
  .then(result => Promise.resolve(result + 1))
  .then(newResult => /* newResult === result + 1 */) 

Having this in mind, you can also return a rejected promise that actually can be caught with the catch method:

somePromiseCall()
  .then(result => Promise.reject('reason'))
  .catch(err => console.log('error', err)) 
发布评论

评论列表(0)

  1. 暂无评论