即
async asyncfunction(){
try{
await method1();
await method2();
}
catch(error){
console.log(error);
}
}
给定 method1() 和 method2() 是异步函数。每个await 方法都应该有一个try/catch 块吗?有没有更干净的方法来写这个?我试图避免“.then”和“.catch”链接。
在等待
await
一元运算符右侧创建的 Promise 时,使用包含多个 await
操作的一个 try/catch 块是可以的:
await
运算符存储其父async
函数的执行上下文并返回到事件循环。当使用其操作数的已确定状态和值进行回调时,await
运算符的执行将恢复。
恢复后,
await
恢复之前保存的执行上下文,并返回操作数承诺的已完成值作为await
表达式的结果,或抛出拒绝操作数的拒绝原因。
try/catch
块调用是保存和恢复之前和之后执行上下文的一部分。因此,多个 await
操作不会干扰它们共享的外部 try
块的行为。 catch
块将被调用,并带有在被拒绝的 try
块中等待的任何承诺的拒绝原因。
未捕获拒绝警告
如果代码
await
的 Promise 不是由 await
运算符的参数表达式创建的,并且没有拒绝处理程序,则在执行 await
运算符应用于它们之前,这些 Promise 不会有拒绝处理程序运行时。
如果在
await
将处理程序添加到此类 Promise 之前触发 try/catch 块,并且它们拒绝,则会发生未捕获的拒绝错误。感谢@EyolRoth 的警告,请参阅他的 answer 以获取案例示例。
建议:如果您需要等待之前创建的且没有错误处理程序的承诺,请仔细考虑。然后检查如何将其创建移动到
await
的操作数表达式。
虽然@traktoranswer是正确的,但我想添加一个非常重要的警告。
以下代码片段不安全:
async function foo() {
try {
const p1 = method1();
const p2 = method2();
await p1;
await p2;
} catch (e) {
console.log(e);
}
}
如果两个 Promise 都被拒绝,则代码将导致 NodeJS 中出现
UnhandledPromiseRejectionWarning
,如果选项 --unhandled-rejections
设置为 throw
(这将成为 Node 15 的默认行为),则可能会终止进程。
为什么会出现这种情况?
在问题的原始代码中,异步方法是顺序调用的;即,如果第一个方法失败(承诺被拒绝),则永远不会调用第二个方法。
但是,本答案开头的代码并行调用这两个异步方法;即,无论第一个方法是否成功,都会调用第二个方法。
在这种情况下,只有第二个方法的承诺中的
await
以第一个方法的成功为条件。这意味着,如果第一个方法失败,则永远不会等待第二个方法(已经开始)的 Promise,因此如果它也失败,则会导致已处理的 Promise 拒绝。
如何克服这种行为?
假设我们希望以相同的方式处理两个拒绝,我们可以使用 Promise.all:
try {
const p1 = method1();
const p2 = method2();
await Promise.all([p1, p2]);
} catch (e) {
console.log(e);
}
只有第一个被拒绝的承诺才会“触发”
catch
子句,而第二个承诺将被默默地忽略而不会导致进程崩溃。
使用 Async.js 库 让我们谈谈如何使用 async.js 库以避免回调地狱。
根据 async.js 的官方网站:Async 是一个实用程序模块,它为使用异步 JavaScript 提供了直接、强大的功能。
Async.js 总共提供了近 70 个左右的函数。现在,我们只讨论其中两个,即 async.waterfall() 和 async.series()。
async.waterfall() 当您想要一个接一个地运行一些任务,然后将前一个任务的结果传递到下一个任务时,此方法非常有用。它需要一个函数“任务”数组和一个最终“回调”函数,该函数在“任务”数组中的所有函数完成后调用,或者使用错误对象调用“回调”。