先追這段程式
本地 Promise 以 Local example failed 拒絕。async 函式在 finally 記錄 cleanup,呼叫者再用 catch 接住失敗。
const trace=[];
async function run(){try{await Promise.reject(new Error('Local example failed'));}finally{trace.push('cleanup');}}
run().catch(error=>console.log(JSON.stringify({message:error.message,trace})));
{"message":"Local example failed","trace":["cleanup"]}| 位置 | 動作 | 結果 |
|---|---|---|
| await rejection | 進入 finally | Local example failed |
| finally | 記錄一次 cleanup | ["cleanup"] |
| catch | 讀原錯誤訊息 | 已處理拒絕 |
結果為何如此
finally 正常結束,保留之前的完成結果;若 return 或 throw,就會覆蓋。這裡是 async 內的 try/finally,並非直接使用 Promise.prototype.finally。例子每個拒絕都有處理。
比較另一種寫法
finally 內 return done 會蓋過失敗,令 async 呼叫變成成功。做了收尾不代表原工作成功。
const trace=[];async function run(){try{await Promise.reject(new Error('Local example failed'));}finally{trace.push('cleanup');return 'done';}}
run().then(value=>console.log(JSON.stringify({value,trace})),error=>console.log(error.message));
{"value":"done","trace":["cleanup"]}試清邊界
收尾本身再拋出 Cleanup failed,catch 會收到哪個錯誤?
查看參考答案
會收到 Cleanup failed,早前錯誤已被取代。如需保留兩項失敗,要明確處理收尾錯誤。
async function run(){try{await Promise.reject(new Error('Local example failed'));}finally{throw new Error('Cleanup failed');}}
run().catch(error=>console.log(error.message));
Cleanup failed