![](/img/trans.png)
[英]Failed conversion from promise syntax for jQuery ajax function to try/catch/finally and async/await?
[英]await in finally block of async function causes PromiseRejectionHandledWarning
我在我的 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();
在 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)
據我了解,我不會在這里留下任何未處理的 promise。 我究竟做錯了什么? finally
應該按設計同步阻止嗎? 如果是,為什么會這樣?
更新 1:
如果我將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()
})
}
更新2:(理解問題)
如果我await
返回的 Promise,問題就解決了。
return await Promise.reject(e)
這讓我明白我做錯了什么。 我打破了await
鏈(部分與在then
/ catch
語法中不返回Promise
同義)。 感謝大家:)
當一個 Promise 拒絕時,必須在當前調用堆棧清除之前對其進行處理,否則將出現未處理的拒絕。 你有:
} catch (e) {
return Promise.reject(e)
} finally {
await cleanup() // remove await here and everything is fine
}
如果刪除await
, someFunctionThatReturnsRejectedPromise
在構造了被拒絕的 Promise 后立即返回,因此Promise.reject(e)
,被拒絕的 ZA5A3F0F287A448982AAC520CFFE4 在main
之后被catch
in 捕獲。 但是如果有任何延遲,被拒絕的 Promise 將不會立即處理; 您的await cleanup()
將意味着被拒絕的 Promise 在someFunctionThatReturnsRejectedPromise
返回之前有一段時間未處理,這意味着main
的catch
無法及時處理被拒絕的 Promise 。
您可以使用的另一種方法是將錯誤包裝在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();
更新的答案替換
Promise.reject(e)
與throw e
;
所以 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
}
}
原因
someFunctionThatReturnsRejectedPromise
方法首先拒絕Promise
。 所以控制流轉到方法main
catch 塊。 后來的cleanup
方法嘗試做同樣的事情。 也就是拒絕已經被拒絕的promise。 因此你得到錯誤
Promise.reject
與throw
子句有點不同。 請參考throw vs Promise.reject
這就是為什么從cleanup()
中刪除await
或從cleanup
方法中刪除return
有效的原因。 因為這會將Promise
從當前控制流中分離出來。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.