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

我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语法同义)。感谢大家 :)


翻过高山走不出你
浏览 458回答 2
2回答

缥缈止盈

当一个 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();

精慕HU

更新的答案替换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与当前控制流分离。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript