點擊一鍵訂閱《雲薦大咖》專欄,獲取官方推薦精品內容,學技術不迷路!
健壯性(Robustness) 是指程序在遇到規範以外的輸入,錯誤和異常時,仍能正常運行。簡單來說,健壯代碼的適應性很強,不會因爲一些異常,就導致程序崩潰。
不健壯的前端代碼體現爲:
- 接口返回異常或報錯時,頁面白屏。
- 用戶做一些非常規操作時,頁面白屏。
如何寫出健壯的前端代碼
要寫出健壯的前端代碼,就要處理規範以外的輸入,錯誤和異常。具體來說,有 4 點:
- 異常處理。
- 輸入檢查。
- 寫法優化。
- 第三方庫的選擇。
下面,我們具體來說。
1. 異常處理
不做異常做處理,輕則導致功能出錯,重則導致頁面白屏。異常處理,可以分爲如下幾種情況。
主動捕獲運行時異常
用 try-catch
捕獲同步代碼的運行時錯誤。如果是異步代碼,需要轉化成 await
的寫法。如:
try {
doSth()
awaitdoSth2()
} catch (e) {
// 處理異常
}
處理意料之外的全局運行時異常
未被處理的 JavaScript 運行時錯誤(包括語法錯誤)發生時, window 會觸發 error 事件。這麼處理:
window.addEventListener(
'error',
(e) => {/* 處理異常 */}
)
當一項資源(如<img>
或<script>
)加載失敗時,加載資源的元素會觸發 error 事件。這麼處理:
const img = new Image();
img.addEventListener(
'error',
(e) => {/* 處理異常 */}
)
img.src = 'xxx'
異步代碼: Promise reject 的處理
Promise 被 reject 時,可以在 then 的第二個參數或 catch 中處理。如:
p().then(onSuccess, onReject)
p().catch(onReject)
Promise reject 沒有被處理的話,window 會觸發 unhandledrejection
事件。可以統一來處理:
window.addEventListener(
'unhandledrejection',
(e) => {/* 處理異常 */}
)
用 Axios 時,接口報錯的通用處理
可以在 Axios 接口返回的攔截器中,加入接口報錯的通用處理。例如:
axios.interceptors.response.use(function (response) {
return response;
}, err => {
// 報錯處理
if(err.response) {
switch (err.response.status) {
case 400: err.message = '請求錯誤(400)'; break;
case 500: err.message = '服務器錯誤(500)'; break;
// ...
}
}
return Promise.reject(error);
})
Vue 的異常處理
app.config.errorHandler = (err, vm, info) => {
// 處理異常
}
React 的異常處理
React 的生命週期函數 ComponentDidCatch
可以捕獲子組件的異常。因此,可以在根組件外包裹一個組件來處理錯誤。如:
class ErrorBoundary extends React.Component {
componentDidCatch(error, info) {
// 處理異常
}
}
使用:
<ErrorBoundary>
<App />
</ErrorBoundary>
2 輸入檢查
當輸入不滿足條件時,要儘早返回或主動報錯。這裏的輸入包括:接口的返回結果,函數的參數,組件的屬性等。
接口返回格式檢查
接口的返回會出現和前端預期不一致的情況。原因可能是:
- 接口的返回結果變更,但未通知前端。
- 一些特殊的請求參數,導致接口的返回和預期值不同。
因此,我們要對接口返回格式做檢查。我們來看個例子:
const res = await fetchList()
const list = res.map(...)
如果接口返回的不是數組,程序就會報錯。可以做類似這樣的優化:
const res = await fetchList()
const list = Array.isArray(res) ? res.map(...) : []
函數參數檢查
JavaScript 是弱類型語言,函數的參數可以傳任意值或不傳參。因此,不對函數參數檢查,會出現一些和預期不一致的情況。比如,期望實現兩數求和的功能:
function sum (a, b) {
return a + b
}
sum(3, 4) // 7。和預期一致
sum() // NaN。和預期不一致
sum('3', 4) // '34'。和預期不一致
對函數參數做檢查,可以這麼優化:
function sum (a, b) {
if(isNaN(parseFloat(a)) || isNaN(parseFloat(b))) {
throw 'param error. param should be a num'
}
return parseFloat(a) + parseFloat(b)
}
推薦使用 TypeScript。可以用它檢查函數參數。上面的代碼用 TypeScript 這麼寫:
function sum (a: number | string, b: number | string) {
return parseFloat(a as string) + parseFloat(b as string)
}
組件屬性檢查
對組件的屬性檢查和函數參數檢查類似,就不做贅述了。
3 寫法優化
很多寫法優化能提升代碼健壯性。這裏介紹 2 點。
1 switch
都需要有 default
來做異常或默認情況的處理。
2 訪問對象或數組前要做判斷
如:a.b.c
改成 a && a.b && a.b.c
。如果用了 TypeScript,可以這麼寫: a?.b?.c
。
4 第三方庫的選擇
使用第三庫,可以減少造輪子,從而提升開發效率。但如果第三方包不健壯,用到第三方包的功能也就不健壯了。
健壯的第三方庫是成熟,穩定的。最好不要選擇以下情況的第三方庫:
- 剛出來不久的。
- 還沒出穩定版的。如果庫遵循的是 語意化版本規範,主版本號爲 0 的都不是穩定版。
- 使用人數很少的。下載量少,star數低。
- 沒有代碼測試的。
健壯性的測試方法
可以用猴子測試來測試代碼的健壯性。
猴子測試(Money Test),也稱搞怪測試。在軟件測試中,測試者可以進行各種稀奇古怪的操作模式,用以測試軟件的健壯性。
這裏推薦一個適用於瀏覽器的猴子測試工具:gremlins.js。工具會對要測試的頁面進行一通亂點。如下圖所示:
提升代碼質量的下一步
提升代碼質量的下一步就是提升代碼的可讀性。我會在下一篇文章中介紹。