在try/catch块中包装promise是正确的方法吗

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

本文关键字:方法 promise 包装 try catch      更新时间:2023-09-26

我有一个函数可以调用promise。关于成功或失败,我想返回一些超出承诺返回的数据。

我认为这可能奏效:

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 })

然而,这并不奏效。如果在thepromise中抛出错误,它将不调用catch块,而是调用foo()的catch块。

处理这个问题的正确方法是什么?我成功地尝试了一次拦截,但我不确定这是最好的方法:

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'
    }
  })
}

任何旨在返回promise的函数都不应该抛出任何类型的异常或错误。

如果是这样的话,它应该被认为是有缺陷的。

要修复有缺陷的方法,不要抛出异常,而是拒绝返回的promise。


有时您无法修复潜在的bug,例如当您使用他人的API时。如果是这种情况,首先也是最重要的一件事就是向原始作者报告错误,以便修复潜在的问题。

报告问题后,您可以用一个简单的实用程序来包装有缺陷的方法来修复问题:

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;
}

这可以称为:

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

如果您愿意接受Promises的扩展,bluebird有一个可以满足您需要的尝试方法:

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

该错误被认为是在.catch()处处理的,它将向链接的.then()返回已解析的promise。您可以将错误throw发送到下一个.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)))