在JavaScript的异步函数中捕获所有承诺拒绝 [英] Catching All Promise Rejections in an Async Function in JavaScript

查看:67
本文介绍了在JavaScript的异步函数中捕获所有承诺拒绝的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当在异步函数中等待多个承诺(javaScript-节点v8.4.0)后,当多个promise抛出拒绝错误时,我遇到了捕获所有错误的问题.

请参考以下javaScript:

作为参考,函数timeoutOne()和timeoutTwo()仅返回分别在1秒和2秒超时后解析值的本机承诺,或者如果我将"deviousState"设置为true,则返回错误.

let deviousState = true;

async function asyncParallel() {
  try {
    let res1 = timeoutOne();
    let res2 = timeoutTwo();
    console.log(`All done with ${await res1} ${await res2}`)
  }
  catch(err) {
    console.log(err)
  }
}
asyncParallel();

let pAll = Promise.all([timeoutOne(), timeoutTwo()]);
pAll.then((val) => {
  console.log(`All done with ${val[0]} ${val[1]}`)
}).catch(console.log);

在两种情况下,只有先返回的承诺才会记录错误.我知道某些promise库中有一种记录所有错误的方法(例如bluebird中的"settle"方法),但是,我不确定本机promise中是否有此方法的类似物?

此外,如果两个承诺都拒绝,则asyncParallel()会记录一个未捕获的错误,并带有最后拒绝的承诺.那是因为异步函数的try/catch块没有内置机制来以这种方式捕获多个拒绝吗?

如果诺言得以解决,那么在这两种情况下,一切工作都是相同的.只是当两者都拒绝时,Promise.all会处理错误,而异步函数版本则指出,未处理的promise错误之一将在节点的未来版本中使该过程崩溃.

反正是否存在尝试/捕获来正确处理此类错误的信息?还是我仍然需要在异步函数中使用Promise.all来确保正确处理了错误?

解决方案

如果两个承诺均被拒绝,则asyncParallel()记录一个未捕获的错误,最后一个承诺将被拒绝.

是-您创建了timeoutTwo()承诺,但从未处理过它的错误(例如在await中使用它).由于await res1中的异常,从未执行过await res2.

(请注意,不是"拒绝最后一个的承诺",而是总是等待第二的承诺).

是不是因为异步函数的try/catch块没有内置机制来以这种方式捕获多个拒绝?

在顺序代码中,不能有多个异常,因此很难提出额外的语法来处理它们.

我仍然需要在异步函数中使用Promise.all来确保正确处理错误吗?

是的,确实如此.如果要并行等待多个promise,则应始终使用Promise.all. await关键字只是随后的.then()调用的糖.

您应该写

async function asyncParallel() {
  try {
    let [val1, val2] = await Promise.all([timeoutOne(), timeoutTwo()]);
    console.log(`All done with ${val1} ${val2}`)
  } catch(err) {
    console.log(err)
  }
}

在两种情况下,只有先返回的承诺才会记录错误.我知道某些promise库中有一种记录所有错误的方法(例如bluebird中的"settle"方法),但是,我不确定本机promise中是否有此方法的类似物?

不,没有. settle的特性对于使用then以及所需的任何值来实现自己来说都是微不足道的:

async function asyncParallel() {
  try {
    let [stat1, stat2] = await Promise.all([
        timeoutOne().then(() => "one fulfilled", () => "one rejected"), 
        timeoutTwo().then(() => "two fulfilled", () => "two rejected")
    ]);
    console.log(`All settled with ${stat1} ${stat2}`)
  } catch(err) {
    console.log(err)
  }
}

I've ran into an issue with catching all the errors when multiple promises throw rejection errors after being awaited in an async function (javaScript - node v8.4.0).

Make reference to the following javaScript:

For reference, the functions timeoutOne() and timeoutTwo() simply return a native promise that resolves a value after a 1 and 2 second timeout respectively, or reject with an error if I set "deviousState" to true.

let deviousState = true;

async function asyncParallel() {
  try {
    let res1 = timeoutOne();
    let res2 = timeoutTwo();
    console.log(`All done with ${await res1} ${await res2}`)
  }
  catch(err) {
    console.log(err)
  }
}
asyncParallel();

let pAll = Promise.all([timeoutOne(), timeoutTwo()]);
pAll.then((val) => {
  console.log(`All done with ${val[0]} ${val[1]}`)
}).catch(console.log);

In both cases only the promise that returns first logs an error. I know that in some promise libraries there is a way to log all the errors (for example the "settle" method in bluebird), however, I'm not sure if there is an analogue to this method in native promises?

Also, if both promises reject, then asyncParallel() logs an uncaught error with the promise that rejects last. Is that because there is no built in mechanism for async function's try / catch blocks to catch multiple rejections in this way?

Everything works the same in both instances if the promises resolve. Its just that when both reject, the Promise.all handles the errors, and the async function version states that one of the unhandled promise errors will crash the process in future versions of node.

Is there anyway for try / catch to handle this type of error correctly? Or do I still need to use a Promise.all inside async functions to make sure that the errors are handled correctly?

解决方案

If both promises reject, then asyncParallel() logs an uncaught error with the promise that rejects last.

Yes - you created the timeoutTwo() promise but never handled its errors (like using it in an await). The await res2 was never executed due to the exception in await res1.

(Notice it's not "the promise that rejects last", but always the promise that is awaited second).

Is that because there is no built in mechanism for async function's try / catch blocks to catch multiple rejections in this way?

In sequential code, there cannot be multiple exceptions, so coming up with extra syntax to deal with them would be hard.

Do I still need to use a Promise.all inside async functions to make sure that the errors are handled correctly?

Yes, exactly that. If you want to wait for multiple promises in parallel, you should always use Promise.all. The await keyword is just sugar for the following .then() call.

You should write

async function asyncParallel() {
  try {
    let [val1, val2] = await Promise.all([timeoutOne(), timeoutTwo()]);
    console.log(`All done with ${val1} ${val2}`)
  } catch(err) {
    console.log(err)
  }
}

In both cases only the promise that returns first logs an error. I know that in some promise libraries there is a way to log all the errors (for example the "settle" method in bluebird), however, I'm not sure if there is an analogue to this method in native promises?

No, there's not. The characteristics of settle are trivial to implement yourself using then, with any values you desire:

async function asyncParallel() {
  try {
    let [stat1, stat2] = await Promise.all([
        timeoutOne().then(() => "one fulfilled", () => "one rejected"), 
        timeoutTwo().then(() => "two fulfilled", () => "two rejected")
    ]);
    console.log(`All settled with ${stat1} ${stat2}`)
  } catch(err) {
    console.log(err)
  }
}

这篇关于在JavaScript的异步函数中捕获所有承诺拒绝的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆