如何处理导致未解决的承诺的异常

时间:2018-12-18 23:49:09

标签: javascript exception callback promise es6-promise

在处理由于不可预见的未捕获异常而无法解决的承诺时,我看到一些不一致的行为。看来,取决于我如何兑现承诺,该承诺是否会解决,而我不明白为什么。

这是错误的功能:

function bad() {
  return new Promise(resolve => {
    setTimeout(() => {
      throw 'unforseen exception!';
      resolve();
    }, 50);
  });
}

如果我通过以下方式调用此函数,它将无法解决:

bad().then(() => console.log('resolved')); // no console logging

try {
  await bad();
} catch(e) {
  console.log(e);
}
console.log('resolved'); // no console logging

但是像这样调用它可以解决:

Promise.resolve().then(bad()).then(() => console.log('resolved')); // console logs "resolved"

这是为什么?编辑:我现在了解自己在做什么错。但是我真正要回答的是下一部分。

当我有一个需要连续执行的诺言链并且即使链中某处出现故障时也需要继续执行时,我如何最好地保护自己免受不可预见的异常的侵害?

我也尝试过使用catch或finally,但它们似乎没有任何区别。一旦达成了未解决的承诺,执行就会失败。

2 个答案:

答案 0 :(得分:1)

问题是bad()异步地引发错误 ,使得调用者无法检测到该错误。如果要在new Promise...段中引发错误,则应调用reject函数:

function bad() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject('bad!');
      resolve();
    }, 50);
  });
}


bad()
  .then(() => console.log('resolved'))
  .catch((err) => console.log(err));

(async () => {
  try {
    await bad();
  } catch(e) {
    console.log(e);
  }
  console.log('await finished');
})();

您的原因

Promise.resolve().then(bad()).then

之所以调用下一个.then是因为then接受函数作为参数,但是您的bad()正在调用bad 的开始,而译员则想出Promise链。如果您通过传递bad作为函数参数而不是调用它,则会看到与原始代码类似的损坏行为-Promise将永远无法解决:

function bad() {
  return new Promise(resolve => {
    setTimeout(() => {
      throw 'unforseen exception!';
      resolve();
    }, 50);
  });
}

// Promise never resolves:
Promise.resolve().then(bad).then(() => console.log('resolved'));

相反,.then(bad())的计算结果为无效,因此.then将立即解决 ,因此解释器将继续处理下一个{{1 }}。

答案 1 :(得分:1)

在此代码中:

new Promise(resolve => {
  setTimeout(() => {
    throw 'unforseen exception!';
    resolve();
  }, 50);
});

抛出异常发生在非异步回调函数中。处理类似问题的方法是在可能抛出的代码上使用try / catch语句:

new Promise((resolve, reject) => {
  setTimeout(() => {
    try {
      throw 'unforseen exception!';

      resolve();
    }
    catch (err) {
      reject(err);
    }
  }, 50);
});