Promise.all with try / catch simulation

时间:2017-03-11 19:53:36

标签: javascript node.js bluebird es6-promise

我目前正在经历,并试图熟悉承诺,我将切入介绍性概念,并了解问题。在NodeJS中,使用库BlueBird。我不想推迟函数调用,我也不会过多地污染代码,即使这是介绍性编码以熟悉这个前提,因为在尝试更高级的概念时,我会迷失在他们身上。我试图使用asyn / await'尝试一下,但上帝的代码很乱,而且没有工作...... 或多或少的指导方针:

  • 我不想使用Promise.settle,我仍然希望在函数拒绝时退出,如果出现错误,我只想留在Catch块中。
  • 我不想以某种奇怪的方式使用async / await,yield或generator来阻止代码的流动,因为这会对预期的做法产生不利影响。
  • 如果处理此问题的预期解决方案是错误的,请不要说它错了,我理解人们的时间很宝贵,但对语言的运作知之甚少,尽可能多的文件可以被扔给我,或者为什么我错的理由比不受欢迎。
  • 我已经在CoffeeScript中看到了这个概念的实现,我现在没有看到转向该语法系统的可行理由,因为我在未来几个月内可能会使用该语言是裸节点后端管理。

Promises包含一个内置的catch机制,如果处理标准的单个Promise,它可以很好地工作。



// Try/Catch style Promises
funcTwo = function(activate) {
  return new Promise(function(resolve, reject) {
    var tmpFuncTwo;
    if (activate === true) {
      tmpFuncTwo = "I'm successful"
      resolve(tmpFuncTwo)
    } else if (activate === false) {
      tmpFuncTwo = "I'm a failure.";
      reject(tmpFuncTwo)
    } else {
      tmpFuncTwo = "Oh this is not good."
      throw new Error(tmpFuncTwo);
    }
  });
}

funcTwo(true)
  .then(val => {
    console.log("1: ", val)
    return funcTwo()
  })
  .catch(e => {
    console.log("2: Err ", e.message)
  })




让我感到有些困惑的是尝试与Promise.all保持相同的前提,错误没有处理,因为throw直接推送到主控制器。 从此代码段抛出的异常永远不会进入Catch块。



funcThree = function(val) {
  return new Promise(function(resolve, reject) {
    if (val > 0)
      resolve((val + 1) * 5)
    else if (val < 0)
      reject(val * 2)
    else
      throw new Error("No work for 0");
  })
}
// Output in Dev Console
/* 
  Extrending to the catch block handling, This will fail, the exception is thrown, and ignores the catch block. Terminating the program.
*/
Promise.all([funcThree(1), funcThree(0), funcThree(-3)])
  .then(function(arr) {
    for (var ind = 0; ind < arr.length; ind++) {
      console.log(arr)
    };
  }, function(arr) {
    console.log(arr)
  })
  .catch(function(e) {
    console.log("Error")
  })
&#13;
&#13;
&#13;

我试过一个简单的工作,但我对这门语言有些新意,并且不确定这是否符合&#34;最佳实践&#34;,因为它们已经钻进了我的脑海来自Python指南。

&#13;
&#13;
// Promise all, exceptionHandling
funcThree = (val) => {
  return new Promise(function(resolve, reject) {
    if (val > 0)
      resolve((val + 1) * 5)
    else if (val < 0)
      reject(val * 2)
    else {
      var tmp = new Error("No work for 0");
      tmp.type = 'CustomError';
      reject(tmp);
    }
  })
}

/*
  This works, and doesn't cause any type of mixup
*/
Promise.all([funcThree(1), funcThree(0), funcThree(-3)])
  .then(
    arr => {
      for (var ind = 0; ind < arr.length; ind++) {
        console.log(arr)
      };
    }, rej => {
      if (rej.type == 'CustomError')
        throw rej;
      console.log(arr)
    })
  .catch(e => {
    console.log("Catching Internal ", e.message)
  })
&#13;
&#13;
&#13;

这是使用Native Promise库以及bluebird

有没有办法更原生地处理这个问题,

关于jfriend00的评论。我的意思是说我不希望除了try-catch块以外的任何东西处理异常。当我尝试使用与普通承诺相同的格式时,事情完全对齐,我的捕获被确认,并且处理错误。由于Promise.all只能解决/拒绝我不认为有一种干净的方式来委托第二个代码片段中第二次调用funcTwo引发的异常。或多或少,我不确定我作为一种解决方法做了什么,&#34;拒绝,检查拒绝是否传递了错误,然后抛出它,如果它确实&#34;,是一个很好的解决方案,或者如果它会在代码扩展时引起一些深层问题。

1 个答案:

答案 0 :(得分:2)

  

由于Promise.all只能解析/拒绝我不认为有一种干净的方式来委托第二个代码片段中第二次调用funcTwo引发的异常。

在你的代码块中:

// Try/Catch style Promises
funcTwo = function(activate) {
  return new Promise(function(resolve, reject) {
    var tmpFuncTwo;
    if (activate === true) {
      tmpFuncTwo = "I'm successful"
      resolve(tmpFuncTwo)
    } else if (activate === false) {
      tmpFuncTwo = "I'm a failure.";
      reject(tmpFuncTwo)
    } else {
      tmpFuncTwo = "Oh this is not good."
      throw new Error(tmpFuncTwo);
    }
  });
}

throwreject()之间没有区别。 Promise构造函数捕获throw并转换为reject()。就个人而言,我更喜欢在这种情况下使用reject(),因为我认为函数调用比异常快一点。

我不知道这是否在规范中编纂,但通常认为拒绝使用Error对象是个好主意。所以,我会写这样的代码:

function funcTwo(activate) {
  return new Promise(function(resolve, reject) {
    if (activate === true) {
      resolve("I'm successful");
    } else {
      let errMsg = activate === false ? "I'm a failure." : "Oh this is not good.";
      reject(new Error(errMsg));
    }
  });
}

承诺解决或拒绝。没有第三个错误条件与拒绝不同。一个例外就是拒绝。因此,如果您要返回三个状态(如上面的代码),那么您必须决定如何将这三个状态放入resolvereject

由于这只是示例代码,因此这里没有具体的建议。如果activate === false实际上不是错误,只是不同类型的完成,不应该在Promise.all()中止您的其他承诺,那么您希望该案例为resolve(),而不是一个reject()。但是,没有硬性和快速的规则是什么 - 它实际上只取决于你想要对呼叫者自然而简单的行为,因此它因情况而异。

此外,如果您不在此处控制funcTwo中的代码,那么您可以在将.catch()处理程序放到Promise.all()之前将其放在Promise.all()上如果您希望Promise.all()逻辑工作,那么可以将特定拒绝转化为解决方案。 Promise chain,因此您可以在将它们传递给更高级别的操作之前修改它们的输出。它类似于在较低级别使用try / catch来捕获和异常并处理它,因此更高级别的代码不必看到它(有时适当)。

  

或多或少我不确定我作为一种解决方法做了什么,“拒绝,检查拒绝是否传递了错误,然后扔掉它,如果它确实”,是一个很好的解决方案,或者它是否会导致代码扩展时出现了一些深层次的问题。

在此处的/* This works, and doesn't cause any type of mixup */ Promise.all([funcThree(1), funcThree(0), funcThree(-3)]).then(arr => { for (var ind = 0; ind < arr.length; ind++) { console.log(arr[index]); } }, rej => { if (rej.type == 'CustomError') throw rej; console.log(arr) }).catch(e => { console.log("Catching Internal ", e.message) }) 代码中:

.catch()

你的第一个拒绝处理程序并没有真正帮助你。它没有做任何你不能在你的reject处理程序中做的事情。让我再说一遍。承诺resolve/* This works, and doesn't cause any type of mixup */ Promise.all([funcThree(1), funcThree(0), funcThree(-3)]).then(arr => { for (var ind = 0; ind < arr.length; ind++) { console.log(arr) }; }).catch(e => { // there is no value for arr here, no result - only a reject reason console.log("Catching Internal ", e.message) if (rej.type === "CustomError") { // do something special for this type of error } // unless you rethrow here, this rejection will be considered handled // and any further chained `.then()` will see the promise as resolved // but since there is no return value, the promise will be resolved // with an undefined result }); 只有两个结果。例外没有第三个结果。在承诺回调中发生的异常只会被拒绝。因此,您的上述代码可以更改为:

funcThree()

如果您希望尽早捕获Promise.all()中的拒绝,以便仍然可以跟踪Promise.settle()中的其余Promise并仍然获得结果,那么您可以获得{ {1}}实施将遵循对其结论的所有承诺,无论有多少拒绝或您可以编写自己的特殊情况:

function funcFour(val) {
    return funcThree(val).catch(err => {
       // catch and examine the error here
       if (err.type === "CustomError") {
           // allow things to continue on here for this specific error
           // and substitute null for the value.  The caller will have
           // to see null as a meaningful result value and separate from
           // a non-null result
           return null;
       } else {
           // Not an error we recognize, stop further processing
           // by letting this promise reject
           throw err;
       }
    });
}

Promise.all([funcFour(1), funcFour(0), funcFour(-3)]).then(arr => {
   // got results, some might be null
   console.log(arr);
}).catch(err => {
   // got some error that made it so we couldn't continue
   console.log(err);
});

我知道这是所有风格的意见,但使用promises的优秀代码的好处之一是你停止使用深度缩进的代码,现在我看到人们放置各种额外的缩进和线条,根本不需要和似乎删除了干净承诺编码的一些好处。

在这种情况下,.then().catch()可以与他们遵循的承诺位于同一行。并且,无需在新行上启动内联函数定义。