简体   繁体   中英

Is wrapping a promise in a try/catch block the proper method?

I have a function that calls a promise. On success or failure I would like to return some data beyond what the promise returns.

I thought this might work:

function foo() {
  const extra = 'bar'
  return thepromise().then((res) => {
    return {
      result: res,
      data: extra
    }
  }, (err) => {
    // this will not happen if an error is thrown in the called promise
    return {
      result: res,
      data: extra
    }
  })
}

foo().then((res) => { }, (err) => { // error result ends up here })

However this does not work. if an error is thrown in the thepromise it will not call the catch block but instead the catch block of foo() .

What is the proper way to handle this? I am successful with a try/catch block but I am not sure this is the best approach:

function foo() {
  const extra = 'bar'
  return new Promise((resolve, reject) => {
    try {
      return thepromise(p)
    } catch (e) {
      reject(e)
    }
  })
  .then(function(res) {
    return {
      result: res,
      data: extra,
      status: 'success'
    }
  }, function(err) {
    return {
      result: err,
      data: extra
      status: 'error'
    }
  })
}

Any function designed to return a promise should not be throwing any sort of exception or error.

If it does, it should be considered buggy.

To fix a buggy method, instead of throwing an exception, reject the returned promise.


Sometimes you're not in a position to fix the underlying bug, such as when you're using someone else's API. If this is the case, the first and most important thing to do is report the bug to the original authors so that the underlying issue can be fixed.

After reporting the issue, you can wrap the buggy method in a simple utility to fix the issue:

function fixBrokenPromise(promise/*, args...*/) {
  var args = Array.prototype.slice.call(arguments, 1),
      ret;
  try {
    ret = promise.apply(null, args);
  } catch (ex) {
    ret = Promise.reject(ex);
  }
  return ret;
}

This can be called as:

fixBrokenPromise(thepromise/*, args you want to pass to thepromise */)
  .then(...resolve...,
        ...reject...);

The error is considered handled at .catch() , which would return a resolved promise to chained .then() . You can throw the error to the next .catch()

 function foo() { const extra = 'bar' return thepromise().then((res) => { return { result: res, data: extra } }, (err) => { throw new Error(JSON.stringify({ result: err || "no rejection reason provided", data: extra })) }) } var thepromise = () => Promise.reject(); foo().then(data => console.log("fulfilled", data)) .catch(err => console.log("catch", JSON.parse(err.message))) 

If you're willing to entertain extensions to Promises, bluebird has a try method that does just what you need:

import Promise from 'bluebird';

// ...

return Promise
  .try(thepromise)
  .then(res => ({
    result: res,
    data: extra
  })
  .catch(err => ({
    result: res,
    data: extra
  });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM