點選一鍵訂閱《雲薦大咖》專欄,獲取官方推薦精品內容,學技術不迷路!
健壯性(Robustness) 是指程式在遇到規範以外的輸入,錯誤和異常時,仍能正常執行。簡單來說,健壯程式碼的適應性很強,不會因為一些異常,就導致程式崩潰。
不健壯的前端程式碼體現為:
介面返回異常或報錯時,頁面白屏。
使用者做一些非常規操作時,頁面白屏。
如何寫出健壯的前端程式碼
要寫出健壯的前端程式碼,就要處理規範以外的輸入,錯誤和異常。具體來說,有 4 點:
1.異常處理。
2.輸入檢查。
3.寫法優化。
4.第三方庫的選擇。
下面,我們具體來說。
1. 異常處理
不做異常做處理,輕則導致功能出錯,重則導致頁面白屏。異常處理,可以分為如下幾種情況。
主動捕獲執行時異常
用 try-catch 捕獲同步程式碼的執行時錯誤。如果是非同步程式碼,需要轉化成 await 的寫法。如:
try {
doSth()
await doSth2()
} 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。工具會對要測試的頁面進行一通亂點。如下圖所示:
提升程式碼質量的下一步
提升程式碼質量的下一步就是提升程式碼的可讀性。我會在下一篇文章中介紹。
金偉強往期精彩文章推薦:
聊聊程式碼質量 - 《學得會,抄得走的提升前端程式碼質量方法》前言
程式碼質量第 5 層 - 只是實現了功能