關(guān)于JavaScript異常捕獲的幾點建議
前言
為了解決JavaScript回調(diào)地獄的問題,ES6+引入了Promise,通過將返回值代理到Promise中,并結(jié)合pending, rejected, fulfilled三種狀態(tài)的轉(zhuǎn)化返回Promise,將異步的返回值存儲在未來某一時刻可以用到的promise中,方便解析。
Promise通過then()鏈的方式調(diào)用,發(fā)生錯誤時通過rejected promise傳遞錯誤,可以像try...catch一樣捕獲和處理異常,但是使用不當(dāng)可能導(dǎo)致意料之外的行為,本文列舉了一些常見的使用錯誤,在使用中應(yīng)當(dāng)注意。
1.then鏈?zhǔn)秸{(diào)用異步,捕獲不到異常
????現(xiàn)象:在.then()鏈中調(diào)用異步函數(shù),某些調(diào)用方式不同會導(dǎo)致捕獲不到異步拋出的異常
const before = () => {
const p = new Promise((resolve, reject) => {
// resolve('before')
console.log('ok');
reject(new Error('error!!!'));
});
return p;
};
const handleClick = () => {
const p = new Promise((resolve, reject) => {
resolve(true);
});
p
// ? catch不到
.then(() => {
before();
})
// .then(before)
// .then(async () => {
// await before();
// })
.then(() => {
console.log('then');
})
.catch(e => {
console.error(e);
});
};??原因
缺少return語句:before()沒有return,返回undefined,無錯誤拋出,后續(xù)的then鏈會繼續(xù)執(zhí)行,但是因為錯誤沒有被捕獲/正確處理,會導(dǎo)致頁面或應(yīng)用程序崩潰。
?疑惑
rejected promise不就是異常嗎,那為什么沒有觸發(fā)呢?
?? The return is implicit under some circumstances
實際上rejected promise并不是異常,如果不被return出去,就不會觸發(fā)error機制(類似的,如果創(chuàng)建一個新的錯誤對象,但是沒有throw,那么同樣也不會觸發(fā)異常)
實際上,rejected promise并不是異常,如果沒有return出去,那么就不會觸發(fā)error
2. try...catch無法捕獲異步函數(shù)中通過return返回的rejected error.
????需要使用await接收異步函數(shù)的返回,再將結(jié)果return出去
const a = async () => {
return new Promise((resolve, reject) => {
reject('error')
})
};
const b = async () => {
try {
// ?捕獲不到
// return a();
const res = await a();
return res;
}
catch (e) {
console.log('catch exception!!!')
}
}
b();
3. 在Promise的構(gòu)造函數(shù)中使用async會導(dǎo)致異常捕獲不到
let p = new Promise(resolve => {
""(); // TypeError
resolve();
});
(async () => {
await p;
})().catch(e => console.log("Caught: " + e)); // Catches it.
let p = new Promise(async resolve => {
""(); // TypeError
resolve();
});
(async () => {
await p;
})().catch(e => console.log("Caught: " + e)); // Doesn't catch it!
??第一段代碼能夠捕獲到異常,因為異常由Promise的構(gòu)造函數(shù)直接reject出去;第二段代碼不能,因為async關(guān)鍵字會隱式生成一個新的promise,由async函數(shù)自身處理。
4.JavaScript Reject V.S. Throw
都是用于拋出異常,reject和throw有什么區(qū)別,適用于什么場景
先簡單對比一下:
- 都可用于觸發(fā)錯誤機制
- reject是promise的一部分,結(jié)合promise使用;throw不受限制
- throw之后的語句都不會執(zhí)行了,reject之后的語句會正常執(zhí)行,但如果reject前邊有return,那么其后的語句同樣也不會繼續(xù)執(zhí)行
但實際上,這倆并沒有優(yōu)劣之分,但是在某種場景下throw是無效的。在promise的回調(diào)中throw可以正常使用,一旦出現(xiàn)異步,throw就無效了。
比如:
new Promise(function() {
setTimeout(function() {
throw 'or nah';
// return Promise.reject('or nah'); also won't work
}, 1000);
}).catch(function(e) {
console.log(e); // doesn't happen
});
正確捕獲的方式:
new Promise((resolve, reject) => {
setTimeout(function() {
reject('or nah');
}, 1000);
}).catch(function(e) {
console.log(e); // works
});
5. 異常的正確處理方式
異常需要被正確捕獲。
嵌套的try...catch
如果代碼中有嵌套的
try...catch,那么異常會被內(nèi)部的catch捕獲:內(nèi)層異常被處理,那么外層就捕獲不到了;內(nèi)層直接throw,那么內(nèi)層try...catch無意義.then鏈的異常捕獲,需要保證異常在UI層被捕獲。不要過早的吞掉異常,需要保證
catch在最終調(diào)用處調(diào)用,避免異常暴露導(dǎo)致程序或頁面崩潰。
小結(jié)
- rejected promise和throw都可用于觸發(fā)異常,沒有優(yōu)劣之分;
- promise回調(diào)中存在異步,那么rejected promise必要要return出去才可被后續(xù)處理,否則返回undefined,即使存在異常也不會被處理,會導(dǎo)致頁面或應(yīng)用程序崩潰;
- promise回調(diào)中的異步函數(shù),執(zhí)行結(jié)果需要被return出去異常才會被捕獲:要么直接作為回調(diào)參數(shù),要么使用async...await執(zhí)行,要么使用return
- 捕獲promise回調(diào)中異步函數(shù)的異常,throw是無效的,創(chuàng)建一個新的rejected promise也是無效的,需要使用當(dāng)前promise的rejecte函數(shù)
- 在promise的構(gòu)造函數(shù)中使用async關(guān)鍵字會導(dǎo)致異常捕獲不到,因為async關(guān)鍵字會隱式生成一個新的promise,由async函數(shù)自身處理
到此這篇關(guān)于關(guān)于JavaScript異常捕獲的幾點建議的文章就介紹到這了,更多相關(guān)JavaScript異常捕獲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
小程序獲取當(dāng)前位置加搜索附近熱門小區(qū)及商區(qū)的方法
這篇文章主要介紹了小程序獲取當(dāng)前位置加搜索附近熱門小區(qū)及商區(qū)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04
JavaScript判斷變量是否為數(shù)組的方法(Array)
這篇文章主要介紹了JavaScript判斷變量是否為數(shù)組的方法(Array),涉及到j(luò)avascript 數(shù)組 變量相關(guān)知識,感興趣的朋友一起學(xué)習(xí)吧2016-02-02
小程序開發(fā)中如何使用async-await并封裝公共異步請求的方法
在平常的項目開發(fā)中肯定會遇到同步異步執(zhí)行的問題,這篇文章主要介紹了小程序開發(fā)中如何使用async-await并封裝公共異步請求的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01
自己做的模擬模態(tài)對話框?qū)崿F(xiàn)代碼
最近做完一個項目,發(fā)現(xiàn)瀏覽器兼容問題,模態(tài)對話框只有IE支持,但是IE9又不能支持帶框架的對話框,那個對話框的大小打死都設(shè)置不了,在網(wǎng)上查說因為好多功能被IE9屏蔽了,于是自己做了一個模擬對話框的東西2012-05-05
javascript稀疏數(shù)組(sparse array)和密集數(shù)組用法分析
這篇文章主要介紹了javascript稀疏數(shù)組(sparse array)和密集數(shù)組用法,分析javascript稀疏數(shù)組和密集數(shù)組的功能、定義與使用方法,需要的朋友可以參考下2016-12-12

