異常處理
異常處理可以使程序在流程上更加完善。
在 JavaScript 中可以使用 throw
拋出異常,使用 try ... catch
捕獲錯誤。
1. throw
throw 語句用來拋出一個用戶自定義的異常。(MDN)
throw 用于拋出一個異常,這種異常通常是程序出現(xiàn)了不符合預(yù)期的錯誤。
alert('出錯前');
throw '發(fā)生了一個錯誤!';
alert('出錯后');
當(dāng)出現(xiàn) throw
時,程序?qū)袛鄨?zhí)行。
如果 throw
發(fā)生在 try ... catch
中,則會執(zhí)行 catch
中的代碼塊,同時將異常信息帶給 catch。
2. try … catch
try…catch 語句標(biāo)記要嘗試的語句塊,并指定一個出現(xiàn)異常時拋出的響應(yīng)。
try ... catch
可以用于捕獲異常,當(dāng)出現(xiàn) throw 時,會結(jié)束 try
內(nèi)的代碼執(zhí)行,直接進入到 catch
,執(zhí)行 catch
內(nèi)的代碼塊。
try {
alert('出錯前');
throw '發(fā)生了一個錯誤!';
alert('出錯后');
} catch (e) { // e 是錯誤信息,名字隨意,符合變量命名規(guī)范就行
alert('出錯了!錯誤是:' + e);
}
需要注意的是,以前 catch 后面的錯誤參數(shù)是必須接收的,否則會報錯。
但 ES2019 中有一個提案,可以選擇性的提供給 catch 參數(shù),所以最新的 chrome 不傳遞錯誤參數(shù)也是可以的。
try {
alert('出錯前');
throw '發(fā)生了一個錯誤!';
alert('出錯后');
} catch {
alert('出錯了!');
}
由于是比較新的提案,所以建議沒有工具參與代碼編譯時,還是寫上錯誤參數(shù)的接收,避免因瀏覽器兼容性造成的問題。
在 try 后面還可以跟 finally
部分,即無論 try 中的代碼塊是否拋出錯誤,都會執(zhí)行 finally
代碼塊。
try {
alert('開始請求數(shù)據(jù),loading 顯示');
throw '沒有網(wǎng)絡(luò)';
alert('請求結(jié)果是:..編不下去了,反正到不了這里');
} catch (e) {
alert('出現(xiàn)錯誤:' + e);
} finally {
alert('關(guān)閉 loading');
}
3. 可以寫條件的 catch 語句
部分文獻記載了如下格式的 try … catch 語法。
try {
throw 'error';
} catch (e if e instanceof TypeError) {
console.log('TypeError');
} catch (e if e instanceof ReferenceError) {
console.log('ReferenceError');
} catch (e) {
console.log(e);
}
但目前主流瀏覽器基本都無法正常運行這種語法的 try … catch 語句,所以不要使用。
如果有類似的需求,可以使用 if 來代替。
try {
throw 'error';
} catch (e) {
if (e instanceof TypeError) {
console.log('TypeError');
} else if (e instanceof ReferenceError) {
console.log('ReferenceError');
} else {
console.log(e);
}
}
4. Error 對象
通過 Error 的構(gòu)造器可以創(chuàng)建一個錯誤對象。當(dāng)運行時錯誤產(chǎn)生時,Error的實例對象會被拋出。Error 對象也可用于用戶自定義的異常的基礎(chǔ)對象。(MDN)
通常在使用 throw 拋出異常時,會拋出一個 Error
對象的實例。
try {
throw new Error('主動拋出一個錯誤');
} catch (e) {
console.error(e);
}
和大部分內(nèi)置對象一樣,Error 實例也可以不使用 new
關(guān)鍵字創(chuàng)建。
try {
throw Error('主動拋出一個錯誤');
} catch (e) {
console.error(e);
}
拋出 Error 實例,可以得到出現(xiàn)異常的文件和對應(yīng)的行號。
除了 Error
,還有幾種預(yù)定義好語義的異常對象。
5. 其他異常對象
URIError
表示以一種錯誤的方式使用全局URI處理函數(shù)而產(chǎn)生的錯誤;TypeError
值的類型非預(yù)期類型時發(fā)生的錯誤;SyntaxError
嘗試解析語法上不合法的代碼的錯誤;ReferenceError
當(dāng)一個不存在的變量被引用時發(fā)生的錯誤;RangeError
當(dāng)一個值不在其所允許的范圍或者集合中拋出的異常;InternalError
表示出現(xiàn)在 JavaScript 引擎內(nèi)部的錯誤。非標(biāo)準(zhǔn)對象,不建議使用;EvalError
本對象代表了一個關(guān)于 eval 函數(shù)的錯誤.此異常不再會被 JavaScript 拋出,但是EvalError對象仍然保持兼容性。
這些異常對象的使用和 Error
幾乎一致。
瀏覽器碰到對應(yīng)的異常,也會拋出。
try {
console.log(notDefinedVariable);
} catch (e) {
console.error(e);
}
因為 notDefinedVariable
并沒有定義,所以瀏覽器會拋出 ReferenceError
異常,同時提示變量沒有定義。
6. 小結(jié)
完整的產(chǎn)品業(yè)務(wù)邏輯流程,基本都要 try ... catch
參與控制,因為出現(xiàn)異常時,還要有對應(yīng)的動作,如網(wǎng)絡(luò)請求異常,則提示用戶重試,或主動進行超時重新請求操作。