溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

JS中異常與錯(cuò)誤怎么正確處理

發(fā)布時(shí)間:2023-04-20 09:16:21 來源:億速云 閱讀:106 作者:iii 欄目:開發(fā)技術(shù)

這篇“JS中異常與錯(cuò)誤怎么正確處理”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JS中異常與錯(cuò)誤怎么正確處理”文章吧。

    1 面向錯(cuò)誤編程

    為什么說面向錯(cuò)誤編程,這里就要向大家發(fā)出靈魂一問,你能確保你寫的每行代碼都是正常的嗎? 假設(shè)你的代碼天衣無縫,但你能確保你調(diào)用別人提供的方法也不會(huì)出現(xiàn)問題嗎? 顯然,我們無法保證每行代碼的正確性,也無法保證調(diào)用別人的方法一定能成功執(zhí)行。所以如何處理錯(cuò)誤就成了重中之重。 這時(shí)候可能就有人說了:“當(dāng)然有可能會(huì)出現(xiàn)問題啊,不然要測(cè)試干嘛?”我們需要知道的是,當(dāng)這個(gè)錯(cuò)誤暴露出來的時(shí)候, 可能就造成了無法估量的損失。測(cè)試人員在進(jìn)行測(cè)試的時(shí)候是不知道我們的代碼是如何寫的,是很有可能測(cè)試時(shí)候漏了一些點(diǎn)的, 而這每個(gè)遺留點(diǎn)都會(huì)成為一個(gè)個(gè)地雷,說不定哪天就爆了。這也是為什么很多公司都特別重視單元測(cè)試的原因。

    1.1 墨菲定律

    墨菲定律講的是一個(gè)事件如果有兩種或兩種以上的方式去做某件事情,而其中一種方式將導(dǎo)致災(zāi)難,則必定有人會(huì)做出這種選擇。 就像一艘船足夠穩(wěn)固,翻船的概率幾乎為零,但是它還是有翻船的可能性,所以就得備好救生衣。 同樣,即使你的代碼出錯(cuò)概率為百萬分之一,但是那百萬分之一一旦發(fā)生,對(duì)使用者來說就是100%,所以必須做好應(yīng)急策略。

    1.2 先判否

    在代碼出錯(cuò)這點(diǎn)上,我們可以假設(shè)一個(gè)極端情況,即我們寫的每行代碼都有可能出錯(cuò)。 所以在寫代碼之前我們就需要考慮到可能出現(xiàn)錯(cuò)誤的情況,在代碼上的體現(xiàn)就是我們可能先寫了一堆錯(cuò)誤的處理,最后才去處理正確的邏輯。 面向錯(cuò)誤編程的核心技巧就是先判否。

    function doSomeThing (params) {
      if (!params.a) return 
      if (params.b !== true) return
      // ...
      // 開始寫正確代碼邏輯
    }

    錯(cuò)誤不是異常

    我們需要明確,異常是代碼運(yùn)行時(shí)發(fā)生的異常信息,如果不處理會(huì)導(dǎo)致代碼無法運(yùn)行。而錯(cuò)誤是代碼在運(yùn)行過程中一個(gè)不期待的結(jié)果。 比如發(fā)起一個(gè) http 請(qǐng)求,即使出現(xiàn)網(wǎng)絡(luò)出錯(cuò)等情況導(dǎo)致請(qǐng)求失敗,但是請(qǐng)求即使失敗了,也應(yīng)該是不影響代碼繼續(xù)運(yùn)行的。 對(duì)于我們來說一個(gè)請(qǐng)求只有一個(gè)結(jié)果,要么成功,要么失敗,而失敗其實(shí)也是一個(gè)結(jié)果,那么這就是一個(gè)錯(cuò)誤。 但是在執(zhí)行 JSON.parse 方法的時(shí)候如果解析出錯(cuò)不做處理,就會(huì)因?yàn)榻馕霎惓6鴮?dǎo)致代碼運(yùn)行終止,那么這就是一個(gè)異常。

    2. js 內(nèi)置的錯(cuò)誤處理

    2.1 Error 類

    當(dāng)運(yùn)行時(shí)錯(cuò)誤產(chǎn)生時(shí),Error 對(duì)象會(huì)被拋出。Error 對(duì)象也可用于用戶自定義的異常的基礎(chǔ)對(duì)象。js還封裝了一些內(nèi)置的標(biāo)準(zhǔn)錯(cuò)誤類型。 如語法錯(cuò)誤的 SyntaxError,類型錯(cuò)誤的 TypeError,以及 ReferenceError、RangeError、URIError、AggregateError、AggregateError、InternalError。

    2.2 throw

    throw 用于拋出一個(gè)異常。經(jīng)常結(jié)合 Error 一起使用。

    2.3 try catch

    try catch 用于捕獲一個(gè)可能出現(xiàn)的未知異常。剛剛提到的 JSON.parse 就是一個(gè)最好的例子,在解析一個(gè)字符串的時(shí)候, 你沒法確保字符串就一定是一個(gè) json 字符串,所以必須使用 try catch 包裹異常,不然就會(huì)發(fā)生代碼運(yùn)行終止。 而我們很多同學(xué)在 try catch 的使用過程中經(jīng)常會(huì)發(fā)生濫用現(xiàn)象,比如使用 try catch 包裹請(qǐng)求錯(cuò)誤:

    try {
      const res = await request()
      if (res) {
        //...
      }
    } catch(err) {
      // ...
      // 請(qǐng)求錯(cuò)誤處理
    }

    我個(gè)人非常反對(duì)這種使用,為什么呢,按照剛剛說的,請(qǐng)求結(jié)果其實(shí)是一個(gè)值,即使請(qǐng)求失敗,返回的也是一個(gè)值。 而在 try 里面即使拿到請(qǐng)求成功的值,在后續(xù)處理 res 的過程中如果發(fā)生語法錯(cuò)誤,這時(shí)也會(huì)拋出異常, 那此時(shí)你還能確定這個(gè) catch 捕獲到的異常是請(qǐng)求失敗了還是處理 res 時(shí)候報(bào)錯(cuò)的嗎? 我之前說過一句話,濫用 try catch 和隨地大小便無異。所以希望大家不要再使用這種方法。

    2.4 Promise.catch

    js 中還提供了內(nèi)置類 Promise,promise 的存在不僅僅是解決了 js 回調(diào)地獄的問題,而且按照 promise 的設(shè)定,promise 必定會(huì)返回一個(gè)結(jié)果。 這個(gè)結(jié)果要么是成功,要么是失敗。這點(diǎn)其實(shí)就和剛剛提到的請(qǐng)求結(jié)果非常搭配,比如 axios 請(qǐng)求庫就使用 promise 返回請(qǐng)求結(jié)果。所以針對(duì)上面的例子我們應(yīng)該這樣

    // request 返回一個(gè) promise
    request()
    .then(res => {
      // 這里處理請(qǐng)求成功
      // ...
      // 如果業(yè)務(wù)代碼可能出錯(cuò),再使用 try catch
      try {
        // ...
      } catch (err) {
        // ...
      }
    })
    .catch()

    3. 錯(cuò)誤處理只有一次

    代碼運(yùn)行出錯(cuò)時(shí),我們只處理一次。如果你能立即確定錯(cuò)誤的處理方案,你就直接處理掉。 當(dāng)你處理不了這個(gè)錯(cuò)誤的時(shí)候,就要把詳細(xì)的錯(cuò)誤結(jié)果包裝好。這樣別人在調(diào)用的時(shí)候就能自己去處理錯(cuò)誤了。

    這里我們繼續(xù)使用請(qǐng)求來舉例,我們?cè)谡?qǐng)求時(shí), 可能因?yàn)?token 過期導(dǎo)致請(qǐng)求 401 導(dǎo)致失敗,你不可能在每個(gè)接口調(diào)用的地方都判斷一次是否 401 吧。 這種 401 導(dǎo)致的失敗是在封裝請(qǐng)求方法的時(shí)候我們就能處理的,具體的請(qǐng)求不需要再去處理, 那我們就不需要把 401 這種錯(cuò)誤告訴具體的請(qǐng)求使用函數(shù),自己處理就行了,我們只需要告訴它錯(cuò)誤了就行。

    但是具體的請(qǐng)求業(yè)務(wù)錯(cuò)誤可能就無法處理了。舉個(gè)常見的例子,比如你獲取一個(gè)列表數(shù)據(jù),我們?cè)谡?qǐng)求時(shí)經(jīng)常和后端約定請(qǐng)求成功碼。經(jīng)??吹接型瑢W(xué)這樣寫:

    request()
      .then(res => {
        // 假設(shè)請(qǐng)求成功碼 0 為成功
        if (res.code === 0) {
          // ...
        } else if (res.code === 1) {
          // ...
          // 參數(shù)錯(cuò)誤
        } else {
          // ...
          // 其他錯(cuò)誤
        }
      })

    同樣,非常不建議這樣使用,為什么呢。因?yàn)榈谝稽c(diǎn),業(yè)務(wù)錯(cuò)誤也是錯(cuò)誤。then 里面處理的是請(qǐng)求成功結(jié)果,按照剛剛說的,如果處理不了錯(cuò)誤就交由具體使用方去處理,而在這里業(yè)務(wù)錯(cuò)誤應(yīng)該交由具體請(qǐng)求方的 catch 去處理。所以應(yīng)該改成:

    request()
      .then(res => {
        // then 里面只會(huì)請(qǐng)求成功,并且能夠成功拿到數(shù)據(jù)
        // ...
      })
      .catch(err => {
        // 獲取到包裝好的錯(cuò)誤信息
        if (err.code === 1) {
          // ...
          // 參數(shù)錯(cuò)誤
        } else {
          // ...
          // 其他錯(cuò)誤
        }
      })

    這樣就能確保整個(gè)錯(cuò)誤的傳遞路徑的正確性,而不是不該你處理的錯(cuò)誤你處理了。 具體在 封裝 axios 的時(shí)候也有提到,就不展開了。

    以上就是關(guān)于“JS中異常與錯(cuò)誤怎么正確處理”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    js
    AI