引入
我們都知道 try catch 無(wú)法捕獲 setTimeout 異步任務(wù)中的錯(cuò)誤,那其中的原因是什么。以及異步代碼在 js 中是特別常見(jiàn)的,我們?cè)撛趺醋霾疟容^?
無(wú)法捕獲的情況
function main() { try { setTimeout(() => { throw new Error('async error') }, 1000) } catch(e) { console.log(e, 'err') console.log('continue...') }}main();這段代碼中,setTimeout 的回調(diào)函數(shù)拋出一個(gè)錯(cuò)誤,并不會(huì)在 catch 中捕獲,會(huì)導(dǎo)致程序直接報(bào)錯(cuò)崩掉。
所以說(shuō)在 js 中 try catch 并不是說(shuō)寫(xiě)上一個(gè)就可以高枕無(wú)憂了。難道每個(gè)函數(shù)都要寫(xiě)嗎,
那什么情況下 try catch 無(wú)法捕獲 error 呢?
異步任務(wù)
上面的栗子稍微改一下,主任務(wù)中寫(xiě)一段 try catch,然后調(diào)用異步任務(wù) task,task 會(huì)在一秒之后拋出一個(gè)錯(cuò)誤。
// 異步任務(wù)const task = () => { setTimeout(() => { throw new Error('async error') }, 1000)}// 主任務(wù)function main() { try { task(); } catch(e) { console.log(e, 'err') console.log('continue...') }}這種情況下 main 是無(wú)法 catch error 的,這跟瀏覽器的執(zhí)行機(jī)制有關(guān)。異步任務(wù)由 eventloop 加入任務(wù)隊(duì)列,并取出入棧(js 主進(jìn)程)執(zhí)行,而當(dāng) task 取出執(zhí)行的時(shí)候, main 的棧已經(jīng)退出了,也就是上下文環(huán)境已經(jīng)改變,所以 main 無(wú)法捕獲 task 的錯(cuò)誤。
事件回調(diào),請(qǐng)求回調(diào)同屬 tasks,所以道理是一樣的。eventloop 復(fù)習(xí)可以看這篇文章
微任務(wù)(promise)的回調(diào)// 返回一個(gè) promise 對(duì)象const promiseFetch = () => new Promise((reslove) => { reslove();})function main() { try { // 回調(diào)函數(shù)里拋出錯(cuò)誤 promiseFetch().then(() => { throw new Error('err') }) } catch(e) { console.log(e, 'eeee'); console.log('continue'); }}promise 的任務(wù),也就是 then 里面的回調(diào)函數(shù),拋出錯(cuò)誤同樣也無(wú)法 catch。因?yàn)槲⑷蝿?wù)隊(duì)列是在兩個(gè) task 之間清空的,所以 then 入棧的時(shí)候,main 函數(shù)也已經(jīng)出棧了。
并不是回調(diào)函數(shù)無(wú)法 try catch
很多人可能有一個(gè)誤解,因?yàn)榇蟛糠钟龅綗o(wú)法 catch 的情況,都發(fā)生在回調(diào)函數(shù),就認(rèn)為回調(diào)函數(shù)不能 catch。
不全對(duì),看一個(gè)最普通的栗子。
// 定義一個(gè) fn,參數(shù)是函數(shù)。const fn = (cb: () => void) => { cb();};function main() { try { // 傳入 callback,fn 執(zhí)行會(huì)調(diào)用,并拋出錯(cuò)誤。 fn(() => { throw new Error('123'); }) } catch(e) { console.log('error'); }}main();結(jié)果當(dāng)然是可以 catch 的。因?yàn)?callback 執(zhí)行的時(shí)候,跟 main 還在同一次事件循環(huán)中,即一個(gè) eventloop tick。所以上下文沒(méi)有變化,錯(cuò)誤是可以 catch 的。
根本原因還是同步代碼,并沒(méi)有遇到異步任務(wù)。
|
新聞熱點(diǎn)
疑難解答
圖片精選