为了账号安全,请及时绑定邮箱和手机立即绑定

在异步函数的 finally 块中等待导致 PromiseRejectionHandled

在异步函数的 finally 块中等待导致 PromiseRejectionHandled

翻过高山走不出你 2022-07-08 17:57:56
我async await在我的 NodeJs 代码中使用,代码结构如下。async function main(){    try {        await someFunctionThatReturnsRejectedPromise()    } catch(e) {        console.log(e)    }}async function someFunctionThatReturnsRejectedPromise() {    try {        await new Promise((resolve,reject) => {            setTimeout(() => {                reject('something went wrong')            }, 1000);        })    } catch(e) {        return Promise.reject(e)    } finally {        await cleanup() // remove await here and everything is fine    }}function cleanup() {    return new Promise(resolve => {        setTimeout(() => {            resolve('cleaup successful')        }, 1000);    })}main();在 finally 块中,我正在做一些async肯定会解决的清理工作。但是这段代码正在抛出PromiseRejectionHandledWarning(node:5710) UnhandledPromiseRejectionWarning: something went wrong(node:5710) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)(node:5710) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.something went wrong(node:5710) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)据我了解,我不会在这里留下任何未处理的承诺。我究竟做错了什么?应该finally按设计同步阻塞吗?如果是,为什么会这样?更新1:如果我转换someFunctionThatReturnsRejectedPromise为好的 ol' thenand catch,它可以正常工作:function someFunctionThatReturnsRejectedPromise() {    return (new Promise((resolve,reject) => {        setTimeout(() => {            reject('something went wrong')        }, 1000);    })).catch(e => {        return Promise.reject(e)    }).finally(() => {        return cleanup()    })}更新2:(理解问题)如果我await返回 Promise,问题就解决了。 return await Promise.reject(e)这让我明白我做错了什么。我打破了await链条(部分与不返回Promisein then/catch语法同义)。感谢大家 :)
查看完整描述

2 回答

?
缥缈止盈

TA贡献2041条经验 获得超4个赞

当一个 Promise 拒绝时,必须在当前调用堆栈清除之前处理它,否则会出现未处理的拒绝。你有:


} catch (e) {

  return Promise.reject(e)

} finally {

  await cleanup() // remove await here and everything is fine

}

如果你 remove await,则在构造被拒绝的 Promise 后立即someFunctionThatReturnsRejectedPromise返回 ,因此被拒绝的 Promise 被in捕获。但是如果有任何延迟,被拒绝的 Promise不会立即处理;你的意愿意味着被拒绝的 Promise 在返回之前的一段时间内未处理,这意味着无法及时处理被拒绝的 Promise。Promise.reject(e)catchmainawait cleanup()someFunctionThatReturnsRejectedPromisemaincatch


您可以使用的另一种方法是将错误包装在 anError而不是 aPromise.reject中,然后检查结果是否为instanceof Errorin main:


window.addEventListener('unhandledrejection', () => console.log('unhandled rejection!'));


async function main() {

  const result = await someFunctionThatReturnsRejectedPromise();

  if (result instanceof Error) {

    console.log('Error "caught" in main:', result.message);

  }

}


async function someFunctionThatReturnsRejectedPromise() {

  try {

    await new Promise((resolve, reject) => {

      setTimeout(() => {

        reject('something went wrong')

      }, 1000);

    })

  } catch (e) {

    return new Error(e);

  } finally {

    await cleanup()

  }

}



function cleanup() {

  return new Promise(resolve => {

    setTimeout(() => {

      resolve('cleaup successful')

    });

  })

}


main();


查看完整回答
反对 回复 2022-07-08
?
精慕HU

TA贡献1845条经验 获得超8个赞

更新的答案替换


Promise.reject(e)与throw e;


所以函数变成


async function someFunctionThatReturnsRejectedPromise() {

   try {

       await new Promise((resolve,reject) => {

           setTimeout(() => {

               reject('something went wrong')

           }, 1000);

       })

   } catch(e) {

       throw e;

   } finally {

       await cleanup() // remove await here and everything is fine

   }

}

原因


someFunctionThatReturnsRejectedPromise方法拒绝第Promise一个。所以控制流转到方法main捕获块。后来cleanup的方法尝试做同样的事情。也就是拒绝已经拒绝的承诺。因此你得到错误


Promise.rejectthrow与子句有点不同。请参考throw vs Promise.reject


这就是为什么删除awaitfromcleanup()或删除returnfromcleanup方法有效的原因。因为这将Promise与当前控制流分离。


查看完整回答
反对 回复 2022-07-08
  • 2 回答
  • 0 关注
  • 350 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信