程式碼質量第 4 層 - 健壯的程式碼

騰訊雲加社群發表於2021-12-31
點選一鍵訂閱《雲薦大咖》專欄,獲取官方推薦精品內容,學技術不迷路!

image.png

健壯性(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。工具會對要測試的頁面進行一通亂點。如下圖所示:

image.png

提升程式碼質量的下一步

提升程式碼質量的下一步就是提升程式碼的可讀性。我會在下一篇文章中介紹。

3金偉強.jpg

金偉強往期精彩文章推薦:

聊聊程式碼質量 - 《學得會,抄得走的提升前端程式碼質量方法》前言
程式碼質量第 5 層 - 只是實現了功能

213.png

《雲薦大咖》是騰訊雲加社群精品內容專欄。雲薦官特邀行業佼者,聚焦於前沿技術的落地及理論實踐之上,持續為您解讀雲時代熱點技術、探索行業發展新機。點選一鍵訂閱,我們將為你定期推送精品內容。

相關文章