javascript - 当错误可能未包含在 promise 中时,我如何使用 promise 来捕获错误?

标签 javascript node.js promise es6-promise

背景

我正在使用 Promises,我有许多函数可能返回也可能不返回 Promise,也可能失败也可能不失败,如下例所示:

//does not return a Promise, simply a string
let goodFun = function(){
    return "I like bananas!";
};

//blows up!
let badFun = function(){
    throw "A general error blaahh!"; 
};

//You get the point ...

由于这些函数可能会或可能不会返回 Promises 并且可能会或可能不会失败,因此我需要等待它们全部执行。为了实现这一点,我有一个函数来调用它们并等待它们的执行:

let asyncFun = function(){
    return Promise.all([badFun(), goodFun()]);
};

问题

到目前为止一切顺利。我的代码调用了 asyncFun,我预计它的一些函数实际上会失败。为了做好准备,我添加了一个陷阱:

let executor = function(){

    let numbsArray = [1, 2, 3];
    let respArray = [];

    for(let num of numbsArray){
        respArray.push(
            asyncFun()
                .catch( error => console.log(`I failed with ${error} and ${num}`))
        );
    }

    return Promise.all(respArray);
};

问题是 catch 根本没有捕捉到任何东西!

即使在调用 executor 的函数中添加一个 catch 也没有捕获到任何东西!

executor()
    .catch(error => console.log("Failed miserably to catch error!"));

研究

我真的不明白为什么我的 catch 子句没有捕捉到异常。为了找出答案,我阅读了这个讨论:

这让我相信我的所有函数 goodFunbadFun 无论如何都必须始终返回一个 promise 。

这让我感到困惑,因为根据 MDN documentation该数组可能包含一个 Promise,或一个 Promise 的结果(如字符串或数字)。

我还想避免在我的函数中添加甚至更多样板代码....

问题:

  1. 我如何修复我的代码,以便捕获可以添加最少的代码或样板代码?

代码

let goodFun = function() {
  return "I like bananas!";
};

let badFun = function() {
  throw "A general error blaahh!";
};



let asyncFun = function() {
  return Promise.all([badFun(), goodFun()]);
};

let executor = function() {

  let numbsArray = [1, 2, 3];
  let respArray = [];

  for (let num of numbsArray) {
    respArray.push(
      asyncFun()
      .catch(error => console.log(`I failed with ${error} and ${num}`))
    );
  }

  return Promise.all(respArray);
};

executor()
  .catch(error => console.log("Failed miserably to catch error!"));

最佳答案

.catches 不工作的原因是错误被同步抛出。代码执行甚至不会执行 .catch() 指令来设置 catch 处理程序,因为错误已经抛出并且代码执行已转到其他地方。如果您将所有内容都包装在一个普通的 try-catch 中,我想您会看到它捕获了您抛出的错误。

例子:

let goodFun = function() {
  return "I like bananas!";
};

//blows up!
let badFun = function() {
  throw "A general error blaahh!";
};

try {
  Promise.all([goodFun(), badFun()])
    .then(results => console.log(results))
    .catch(error => console.error(error))
} catch (e) {
  console.error("Wups, I caught an error. This wasn't supposed to happen.", e);
}

This is confusing for me, because according to the MDN documentation the array may contain a Promise, or a result from one (like a string, or a number).

MDN 文档绝对正确,但是如果 badFun() 抛出错误,Promise.all 对此无能为力,因为程序流程将沿着调用堆栈向下寻找可以捕获抛出的错误的东西。

如果您不确定某些代码是同步的还是基于 promise 的(或者它是否会抛出同步错误),您可以使用它来安全地包装一个 promise:

function executeSafe(action) {
    return Promise.resolve().then(action);
}

这将保护 action() 免受任何发生的“繁荣”的影响。

例子:

let executeSafe = 
  action => Promise.resolve().then(action);

let goodFun = 
  () => "I like bananas!";

//blows up!
let badFun = 
  () => { throw "A general error blaahh!" };

Promise.all([goodFun, badFun].map(executeSafe))
  .then(results => console.log(results))
  .catch(error => console.error(error))

仅供引用,如果您使用的是 Bluebird,那么它有一个内置方法 Promise.try,其目的与上面的 executeSafe 相同: Promise.all([goodFun, badFun].map(Promise.try)).

这是您的完整示例并进行了必要的修改:

let executeSafe =
  action => Promise.resolve().then(action);

let goodFun =
  () => "I like bananas!";

//blows up!
let badFun =
  () => {
    throw "A general error blaahh!"
  };

let asyncFun =
  () => Promise.all([goodFun, badFun].map(executeSafe));

let executor = function() {
  let numbsArray = [1, 2, 3];

  return Promise.all(numbsArray.map(num =>
    asyncFun()
    .catch(error => console.log(`I failed with ${error} and ${num}`))
  ));
}

executor();

这里是 executor 之外的 .catch:

let executeSafe =
  action => Promise.resolve().then(action);

let goodFun =
  () => "I like bananas!";

//blows up!
let badFun =
  () => {
    throw "A general error blaahh!"
  };

let asyncFun =
  () => Promise.all([goodFun, badFun].map(executeSafe));

let executor = function() {
  let numbsArray = [1, 2, 3];

  return Promise.all(numbsArray.map(asyncFun));
}

executor().catch(error => console.error("Miserably failed to catch anything.", error));

关于javascript - 当错误可能未包含在 promise 中时,我如何使用 promise 来捕获错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42808381/

相关文章:

javascript - 如何将 $promise 返回的数据分配给全局变量

javascript - 如何引用从链式函数返回的 promise ?

javascript - 为什么以下代码不返回所有数组元素的总和?

javascript - 为什么不显示错误消息

javascript - 需要时水平滚动列表居中

javascript - 使用 node-mocks-http 测试没有发出事件的服务

node.js - Mongoose for var in loop 在子文档中

javascript - xhr 超时在 ie11 中给出无效状态错误

javascript - 在 jqGrid 的 loadBeforeSend 上设置 Url

php - 加载具有动态内容的页面