[英]await in finally block of async function causes PromiseRejectionHandledWarning
I'm using async
await
in my NodeJs code and the code structure is something as follows.我在我的 NodeJs 代码中使用async
await
,代码结构如下。
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();
In the finally block, I'm doing some async
cleanup that will surely resolve.在 finally 块中,我正在做一些肯定会解决的async
清理。 But this code is throwing PromiseRejectionHandledWarning
但是这段代码正在抛出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)
As far as I understand, I'm not leaving any promise unhandled here.据我了解,我不会在这里留下任何未处理的 promise。 What am I doing wrong?我究竟做错了什么? Should finally
block by synchronous by design? finally
应该按设计同步阻止吗? If yes, why so?如果是,为什么会这样?
Update 1:更新 1:
If I convert someFunctionThatReturnsRejectedPromise
to good ol' then
and catch
, it works with no problems:如果我将someFunctionThatReturnsRejectedPromise
转换为 good ol' then
并catch
,它可以正常工作:
function someFunctionThatReturnsRejectedPromise() {
return (new Promise((resolve,reject) => {
setTimeout(() => {
reject('something went wrong')
}, 1000);
})).catch(e => {
return Promise.reject(e)
}).finally(() => {
return cleanup()
})
}
Update 2: (Understood the problem)更新2:(理解问题)
If I await
the returning Promise, problem is solved.如果我await
返回的 Promise,问题就解决了。
return await Promise.reject(e)
And this makes me understand what I was doing wrong.这让我明白我做错了什么。 I was breaking the await
chain (partially synonymous to not returning a Promise
in then
/ catch
syntax).我打破了await
链(部分与在then
/ catch
语法中不返回Promise
同义)。 Thanks everyone:)感谢大家:)
When a Promise rejects, it must be handled before the current call stack clears , or there will be an unhandled rejection.当一个 Promise 拒绝时,必须在当前调用堆栈清除之前对其进行处理,否则将出现未处理的拒绝。 You have:你有:
} catch (e) {
return Promise.reject(e)
} finally {
await cleanup() // remove await here and everything is fine
}
If you remove await
, the someFunctionThatReturnsRejectedPromise
returns immediately after the rejected Promise is constructed, so the Promise.reject(e)
, the rejected Promise, is caught by the catch
in main
right after.如果删除await
, someFunctionThatReturnsRejectedPromise
在构造了被拒绝的 Promise 后立即返回,因此Promise.reject(e)
,被拒绝的 ZA5A3F0F287A448982AAC520CFFE4 在main
之后被catch
in 捕获。 But if there's any delay, the rejected Promise will not be handled immediately;但是如果有任何延迟,被拒绝的 Promise 将不会立即处理; your await cleanup()
will mean that the rejected Promise goes unhandled for a period of time, before someFunctionThatReturnsRejectedPromise
returns, which means that main
's catch
can't handle the rejected Promise in time.您的await cleanup()
将意味着被拒绝的 Promise 在someFunctionThatReturnsRejectedPromise
返回之前有一段时间未处理,这意味着main
的catch
无法及时处理被拒绝的 Promise 。
Another method you could use would be to wrap the error in an Error
instead of a Promise.reject
, and then check if the result is an instanceof Error
in main
:您可以使用的另一种方法是将错误包装在Error
中而不是Promise.reject
中,然后检查结果是否是main
中的instanceof Error
:
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();
Updated answer replace the更新的答案替换
Promise.reject(e)
with throw e
; Promise.reject(e)
与throw e
;
so the function becomes所以 function 变成
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
}
}
Reason原因
someFunctionThatReturnsRejectedPromise
method rejects the Promise
first. someFunctionThatReturnsRejectedPromise
方法首先拒绝Promise
。 So the control flow went to method main
catch block.所以控制流转到方法main
catch 块。 Later cleanup
method tries to do the same.后来的cleanup
方法尝试做同样的事情。 Which is to reject the already rejected promise.也就是拒绝已经被拒绝的promise。 Thus you get the error因此你得到错误
Promise.reject
is a bit different from throw
clause. Promise.reject
与throw
子句有点不同。 Please refer throw vs Promise.reject请参考throw vs Promise.reject
Which is why removing the await
from cleanup()
or removing the return
from cleanup
method works.这就是为什么从cleanup()
中删除await
或从cleanup
方法中删除return
有效的原因。 Because that will detach the Promise
from the current control flow.因为这会将Promise
从当前控制流中分离出来。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.