从嵌套的 async/await 函数中捕获错误

Posted

技术标签:

【中文标题】从嵌套的 async/await 函数中捕获错误【英文标题】:Catching errors from nested async/await functions 【发布时间】:2017-04-12 11:15:46 【问题描述】:

我在 node 4.3 脚本中有一个函数链,看起来像回调 -> 承诺 -> async/await -> async/await -> async/await

像这样:

const topLevel = (resolve, reject) => 
    const foo = doThing(data)
    .then(results => 
        resolve(results)
    )
    .catch(err => 
        reject(err)
    )


async function doThing(data) 
    const thing = await doAnotherThing(data)
    return thing


async function doAnotherThing(data) 
    const thingDone = await etcFunction(data)
    return thingDone

(之所以没有一路async/await是因为顶层函数是一个任务队列库,表面上不能运行async/await风格)

如果etcFunction() 抛出,error 是否会一直冒泡到顶层Promise

如果没有,我该如何冒泡errors?我需要像这样将每个await 包装在try/catchthrow 中吗?

async function doAnotherThing(data) 
   try 
     await etcFunction(data)
    catch(err) 
     throw err  
   

【问题讨论】:

什么是makePromise "顶层函数是一个任务队列库,表面上不能以异步/等待方式运行" - 队列库没有理由不能使用async functions 作为任务。你真的不应该处理回调。如果您需要使用采用回调样式的特定队列库,请使用包装函数。 @Bergi makePromise 实际上是一个 async 函数,但由于它是从非async 环境调用的,所以我将其视为承诺。回复:我同意,我最终会尝试并承诺它,但我可以同时有可靠的错误冒泡吗? @Bergi 我从 sn-p 中删除了makePromise 位以澄清——顶层调用的第一个函数是async function,我将其视为常规Promise @Bergi 是的,感谢您发现该错误和其他错误-我应该只是复制实际代码而不是尝试用伪代码重新创建 【参考方案1】:

如果etcFunction() 抛出,错误会一直冒泡到async functions 吗?

是的。最外层函数返回的承诺将被拒绝。不需要try … catch(e) throw e; ,这就像在同步代码中一样毫无意义。

...一直冒泡到最顶层的 Promise?

没有。您的 topLevel 包含多个错误。如果您不从then 回调中return doThing(data),它将被忽略(甚至不等待)并且拒绝保持未处理状态。你必须使用

.then(data =>  return doThing(data); )
// or
.then(data => doThing(data))
// or just
.then(doThing) // recommended

一般来说,你的函数应该是这样的:

function toplevel(onsuccess, onerror) 
    makePromise()
    .then(doThing)
    .then(onsuccess, onerror);

没有不必要的函数表达式,没有.then(…).catch(…) antipattern(这可能导致onsuccessonerror被调用)。

【讨论】:

【参考方案2】:

我知道这个问题很老,但是正如你的问题所写的那样,doAnotherThing() 函数不是不必要的,因为它只是包装了etcFunction()

所以你的代码可以简化为:

async function topLevel()
  let thing = await doThing(data)
  let thingDone = await etcFunction(data)
  //Everything is done here...


//Everything starts here...
topLevel()

【讨论】:

我认为这是演示嵌套等待调用的模拟代码【参考方案3】:

我刚刚遇到了一个类似的问题,我的嵌套错误似乎没有冒泡到我的***函数。

对我来说,解决方法是从我的嵌套函数中删除“try/catch”并允许抛出错误。

【讨论】:

以上是关于从嵌套的 async/await 函数中捕获错误的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序捕获async/await函数异常实践

如何使用 async/await 编写 .then 函数,以便捕获来自 axios 的响应(在单独的文件和方法中,在 vue 中)

嵌套的 try、catch 和 async、await 请求

为啥 async / await 函数运行两次?

async/await是如何捕获异常的?

async await 的 实质 本质