簡體   English   中英

在異步 function 的 finally 塊中等待導致 PromiseRejectionHandledWarning

[英]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' thencatch ,它可以正常工作:

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
}

如果刪除awaitsomeFunctionThatReturnsRejectedPromise在構造了被拒絕的 Promise 后立即返回,因此Promise.reject(e) ,被拒絕的 ZA5A3F0F287A448982AAC520CFFE4 在main之后被catch in 捕獲。 但是如果有任何延遲,被拒絕的 Promise 將不會立即處理; 您的await cleanup()將意味着被拒絕的 Promise 在someFunctionThatReturnsRejectedPromise返回之前有一段時間未處理,這意味着maincatch無法及時處理被拒絕的 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.rejectthrow子句有點不同。 請參考throw vs Promise.reject

這就是為什么從cleanup()中刪除await或從cleanup方法中刪除return有效的原因。 因為這會將Promise從當前控制流中分離出來。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM