如果可能没有包含在承诺中,我如何使用promises来捕获错误?

时间:2017-03-15 11:23:46

标签: 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,无论如何,都必须始终回报承诺。

这对我来说很困惑,因为根据MDN documentation,数组可能包含一个Promise,或一个结果(如字符串或数字)。

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

问题:

  1. 如何修复我的代码,以便捕获工作添加最小代码或样板代码?
  2. 代码

    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!"));

1 个答案:

答案 0 :(得分:2)

.catch es无效的原因是错误被同步抛出。代码执行永远不会执行.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);
}




  

这对我来说很困惑,因为根据MDN文档,数组可能包含一个Promise,或一个结果(如字符串或数字)。

MDN文档是绝对正确的,但是如果badFun()引发错误,那么Promise.all无法做任何事情,因为程序流将沿着调用堆栈向下飞行寻找能够捕获抛出的错误的东西。

如果您不确定某些代码是同步的还是基于承诺的(或者它是否会引发同步错误),您可以使用它来安全地将其包装为承诺:

function executeSafe(action) {
    return Promise.resolve().then(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();




这里是.catch之外的executor



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