Node.js js 的執行是單線程的,在 Node14 及以前的版本,同步任務同拋錯未處理程序則會終止,異步任務同拋錯未處理則不會,而是出一個 warning, 提示有 UnhandledPromiseRejectionWarning 的異常。
而在Node14以後的版本,就算是異步任務同拋錯未處理程序也會直接終止了。
Node14及以前的版本代碼示例:
PS: 加一個sleep 函數的目的只是讓程序別馬上退出,驗證是否是拋錯導致的進程退出。
function sleep(ms) {
console.log('123213xxx')
return new Promise(resolve => setTimeout(resolve, ms));
}
async function name2(params) {
throw new Error('test2');
}
name2()
sleep(1000000)
結果如下圖:
加入 unhandledRejection 異常事件的捕獲之後
function sleep(ms) {
console.log('123213xxx')
return new Promise(resolve => setTimeout(resolve, ms));
}
async function name2(params) {
throw new Error('test2');
}
name2()
sleep(1000000)
process.on('unhandledRejection', ()=>{
console.log('xxxxxxxxx')
// process.exit(1)
})
結果如上圖: 輸出了 console.log('xxxxxxxxx'), 警告日誌也沒有了
Node14及以前 unhandledRejection 只能捕獲異步異常, uncaughtException 只能捕獲同步異常, 監聽了 uncaughtException 和 unhandledRejection則不會直接退出主進程,除非手動退出。
在Node14以後的版本
unhandledRejection 還是隻能捕獲異步異常,但是 uncaughtException 可以同時catch同步和異步異常,當同時設置了 unhandledRejection 和 uncaughtException 時, 如果是異步的error,則只有 unhandledRejection 會監聽到,uncaughtException 不會監聽到。
Node14以後的版本代碼示例如下
function sleep(ms) {
console.log('123213xxx')
return new Promise(resolve => setTimeout(resolve, ms));
}
async function name2(params) {
throw new Error('test2');
}
name2()
sleep(1000000)
// uncaughtException catch 到了異步任務
process.on('uncaughtException', ()=>{
console.log('xxxxxxxxx123123')
// process.exit(0)
})
當同時設置了 unhandledRejection 和 uncaughtException 時, 異步的error,則只有 unhandledRejection 會監聽到,uncaughtException 不會監聽到。
function sleep(ms) {
console.log('123213xxx')
return new Promise(resolve => setTimeout(resolve, ms));
}
async function name2(params) {
throw new Error('test2');
}
name2()
sleep(1000000)
process.on('unhandledRejection', ()=>{
console.log('xxxxxxxxx')
// process.exit(1)
})
process.on('uncaughtException', ()=>{
console.log('xxxxxxxxx123123')
// process.exit(0)
})
throw new Error('test2');
延展:
有些服務可能會自己做優雅重啓,會在代碼了同時設置unhandledRejection 和 uncaughtException 的監聽時,出現異常時重啓服務,一般會在回調加入一些釋放資源的操作,比如關閉數據庫的連接,關閉http的連接等,但是這裏要注意,如果在高併發的情況下,兩個事件如果同時正在處理,要注意判斷上述的資源是否已經關閉/釋放,再決定執行代碼,不然關閉/釋放兩次可能會導致報錯。
更好的處理是,對於 Node14以後的版本,只設置 uncaughtException 的監聽,就不會出現多個事件同時執行的情況了。