JavaScript代碼不能被阻斷的穩(wěn)定性建設
背景
穩(wěn)定性建設之JavaScript代碼不能被阻斷
js代碼可能會因為某些原因,導致出錯,進而整個后續(xù)代碼有可能都被阻斷。直接影響線上的穩(wěn)定性
最常見的js被阻斷的情況
console.log(111) // 預期 a = {} // 結(jié)果 a = undefined a.a = 1 console.log(222) // js代碼不能執(zhí)行到這一行
這個代碼很明顯會報錯,在a.a = 1
這一行開始報錯,后續(xù)的js代碼被阻斷了,console.log(222)
打印不出來
解決辦法
- 解決辦法也很簡單,用 try...catch... 捕獲住錯誤就好了
console.log(111) try { // 預期 a = {} // 結(jié)果 a = undefined a.a = 1 } catch (e) { console.error(e) } console.log(222) // js代碼可以執(zhí)行到這一行
容易被我們忽視的點
1. 沒考慮到錯誤上報
- 上面的demo沒有考慮錯誤上報,發(fā)生錯誤時,外部根本捕獲不到(即使你接入了sentry類的產(chǎn)品),因為error被try catch給吃掉了
try { // 預期 a = {} // 結(jié)果 a = undefined a.a = 1 } catch (e) { console.error(e) // 公司內(nèi)部的上報函數(shù) someReportFunction('sendEvent', { name: 'try_catch_error', params: { errorMsg: e.message, errorStack: e.stack }, }); }
2. 錯用throw
隨便點開一篇文章,就有人在誤人子弟,教別人用 throw, throw這個東西是不能亂用的,因為他會阻斷代碼,重要的事情說三遍,throw會阻斷代碼,throw會阻斷代碼,throw會阻斷代碼
例如:
console.log(111) try { // 預期 a = {} // 結(jié)果 a = undefined a.a = 1 } catch (e) { console.error(e) throw e // throw會阻斷代碼,導致下面不執(zhí)行 } console.log(222) // 不能執(zhí)行到這一行
當然throw也不是一無是處,但是,他只能在try{ 里面使用 },不能在try之外的地方使用throw,包括catch
console.log(111) try { throw new Error(111) } catch (e) { console.error(e) } console.log(222)
function getData () { if (...) { ... } else { throw new Error(111) } } console.log(111) try { getData() } catch (e) { console.error(e) } console.log(222)
3. 異步代碼catch不到,還是會被阻斷
console.log(111111111) try { setTimeout(() => { a = undefined a.a = 1 // 代碼被阻斷于此 console.log('error') // 不能執(zhí)行到這一行 }, 0) } catch (e) { console.error(e) // 異步代碼catch不到 } console.log(222222222) setTimeout(() => { console.log('setTimeout') // 瀏覽器可以執(zhí)行到這一行,node的不行(node14和16版本都test了) }, 2000)
4. import()和require()的錯誤捕獲表現(xiàn)不一致
// a.js console.log(111111111) try { require('./b.js') } catch (e) { console.log('error') // 錯誤會被正常catch到 console.error(e) } console.log(222222222) setTimeout(() => { console.log('setTimeout') }, 2000) // b.js console.log(1) a = undefined a.a = 1 console.log(2) // 結(jié)果打印 (require被正常捕獲) 111111111 1 error TypeError: Cannot set property 'a' of undefined ... ... 222222222 setTimeout
- 同樣的代碼換成,import()
// a.js console.log(111111111) try { import('./b.js') } catch (e) { console.log('error') // 錯誤沒有被catch到 console.error(e) } console.log(222222222) setTimeout(() => { console.log('setTimeout') }, 2000) // b.js console.log(1) a = undefined a.a = 1 console.log(2) // 結(jié)果打印 (import的 錯誤沒有被catch到) 111111111 222222222 1 (node:92673) UnhandledPromiseRejectionWarning: TypeError: Cannot set property 'a' of undefined ... setTimeout
正確捕獲import()的方式:其實import()是一個promise,用promise的方法去catch就好了
import('./b.js') .catch(e => { console.log('error') console.error(e) })
結(jié)論:
- try catch 不能捕獲import()模塊的錯誤,require可以被捕獲
- import() 用promise的方法去catch就好了
背景:
- require是運行時加載(可以理解為,函數(shù)調(diào)用)
- import()是動態(tài)import,會延遲加載,是異步任務(微任務),是promise
以上就是JavaScript代碼不能被阻斷的穩(wěn)定性建設的詳細內(nèi)容,更多關于JavaScript穩(wěn)定建設的資料請關注腳本之家其它相關文章!
相關文章
超越Node.js的JavaScript運行環(huán)境Bun.js功能特性詳解
這篇文章主要為大家介紹了超越Node.js的JavaScript運行環(huán)境Bun.js功能特性詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09