博客 / 詳情

返回

詳解 Node.js unhandledRejection 和 uncaughtException 事件

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)

結果如下圖:
image.png

加入 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)
})

image.png

結果如上圖: 輸出了 console.log('xxxxxxxxx'), 警告日誌也沒有了

Node14及以前 unhandledRejection 只能捕獲異步異常, uncaughtException 只能捕獲同步異常, 監聽了 uncaughtExceptionunhandledRejection則不會直接退出主進程,除非手動退出。

在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)
})

image.png

當同時設置了 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');

image.png

延展:

有些服務可能會自己做優雅重啓,會在代碼了同時設置unhandledRejectionuncaughtException 的監聽時,出現異常時重啓服務,一般會在回調加入一些釋放資源的操作,比如關閉數據庫的連接,關閉http的連接等,但是這裏要注意,如果在高併發的情況下,兩個事件如果同時正在處理,要注意判斷上述的資源是否已經關閉/釋放,再決定執行代碼,不然關閉/釋放兩次可能會導致報錯。

更好的處理是,對於 Node14以後的版本,只設置 uncaughtException 的監聽,就不會出現多個事件同時執行的情況了。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.