JavaScript錯誤處理操作實例詳解

本文實例講述了JavaScript錯誤處理操作。分享給大家供大家參考,具體如下:

創(chuàng)新互聯(lián)成立于2013年,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站制作、做網(wǎng)站網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元平潭做網(wǎng)站,已為上家服務(wù),為平潭各地企業(yè)和個人服務(wù),聯(lián)系電話:13518219792

良好的錯誤處理機制可以讓用戶得到及時的提醒,所以讓我們來看看 JavaScript 提供了哪些針對錯誤處理的工具和方法吧O(∩_∩)O~

1 try-catch 語句

ECMA-262 第 3 版引入了 try-catch 語句,這時 JavaScript 處理異常的標(biāo)準(zhǔn)方式:

try{
  //可能會導(dǎo)致錯誤的代碼
} catch (error){
  //錯誤處理
}

如果 try 塊中的代碼發(fā)生了錯誤,會立即執(zhí)行 catch 塊的代碼。 catch 塊有一個包含錯誤信息的對象,它有一個 message 屬性,表示的是瀏覽器給出的錯誤消息:

<script type="text/javascript">
  try {
    window.someNonexistenceFunction();
  } catch (error) {
    console.log(error.message);
  }
</script>

message 屬性是所有的瀏覽器都支持的屬性,所以在跨瀏覽器編程中,最好只使用這個屬性。

1.1 finally 子句

finally 子句是可選的,如果使用了 finally 子句,里面包含的代碼是絕對會被執(zhí)行的!甚至連 return 語句都無法阻止它被執(zhí)行:

<script type="text/javascript">
  function testFinally() {
    try {
      return 2;
    } catch (error) {
      return 1;
    } finally {
      return 0;
    }
  }
  console.log(testFinally());//0
</script>

IE7 及更早的版本有一個 bug:除非有 catch 子句,否則 finally 中的代碼永遠不會被執(zhí)行!IE8 修復(fù)了這個 bug。

注意:只要在代碼中使用了 finally 子句,那么不管 return 放在 try 還是 catch 語句中,都會被忽略!

1.2 錯誤類型

當(dāng)錯誤發(fā)生時,會拋出相應(yīng)類型的錯誤對象。ECMA-262 定義了 7 種錯誤類型:

  • Error
  • EvalError
  • RangeError
  • ReferenceError
  • SyntaxError
  • TypeError
  • URIError

1.2.1 Error

Error 是基類型,即其他的錯誤類型都是從 Error 繼承來的??梢岳?Error 來自定義錯誤類型。

1.2.2 EvalError

EvalError 是在使用 eval() 函數(shù)發(fā)生異常時被拋出。怎么才算是異常呢?如果沒有把 eval() 當(dāng)作函數(shù)來使用,就會拋出 EvalError:

new eval();//拋出 EvalError
eval = foo;//拋出 EvalError

實際開發(fā)中很少這樣使用 eval() 函數(shù)的(除非腦袋秀逗了O(∩_∩)O~),所以很少會遇到 EvalError。

1.2.3 RangeError

RangeError 會在數(shù)值超出規(guī)定范圍時被拋出。比如在定義數(shù)組時,指定了數(shù)組不支持的數(shù)組項數(shù),就會拋出這個錯誤:

var item1 = new Array(-20);//拋出 RangeError
var item1 = new Array(Number.MAX_VALUE);//拋出 RangeError

1.2.4 ReferenceError

找不到對象時,會拋出 ReferenceError(這就是瀏覽器的知名的 “object expected” 錯誤)。一般在訪問不存在的變量時,會拋出這個錯誤:

var obj = x;//x 還未被聲明,所以拋出 ReferenceError

1.2.5 SyntaxError

如果把帶著錯誤語法的字符串傳入 eval() 函數(shù)時,就會拋出 SyntaxError:

eval("a ++ b");//拋出 SyntaxError

eval() 函數(shù)之外的語法錯誤,會導(dǎo)致 JavaScript 立即停止執(zhí)行,所以不會拋出這個錯誤!

1.2.6 TypeError

如果變量中保存著意外的類型,或者訪問不存在的方式時,就會拋出 TypeError。這個錯誤比較常見:

var o = new 10;//拋出 TypeError
alert("name" in true);//拋出 TypeError
Function.prototype.toString.call("name");//拋出 TypeError

如果傳遞給函數(shù)的參數(shù)類型與預(yù)期類型不符,也會拋出這個錯誤。

1.2.7 URIError

使用 encodeURI() 或者 decodeURI() 時,URI 的格式不正確,就會拋出 URIError 錯誤。一般很少發(fā)生,因為這兩個函數(shù)有著非常高的容錯性O(shè)(∩_∩)O~

可以針對這些錯誤類型進行恰當(dāng)?shù)奶幚恚?/p>

try{
  someFunction();
} catch (error){
  if (error instanceof TypeError){
    //處理類型錯誤
  }
  ...
}

因為包含在 message 中的消息會因瀏覽器而異,所以在跨瀏覽器編程中,最好直接檢查這些錯誤類型。

1.3 合理使用 try-catch

try-catch 最適合用于那些我們無法控制的錯誤,比如使用了一個開源庫中的函數(shù),而我們無法修改源代碼的情況。

而對于自定義的函數(shù),驗證函數(shù)參數(shù)類型是否合法的情況,就不應(yīng)該使用 try-catch,因為這個函數(shù)是我們可以修改的,在使用參數(shù)前先進行驗證才是正途。

2 拋出錯誤

throw 操作符可以拋出自定義的錯誤,必須要指定一個值,這個值可以是任意類型。代碼在遇到 throw 操作符時,會立即停止執(zhí)行。只有在 try-catch 語句捕獲到被拋出的值時,才會繼續(xù)執(zhí)行。

通過使用之前說過的內(nèi)置錯誤類型,可以模擬瀏覽器錯誤。這些錯誤類型的構(gòu)造函數(shù)都接收一個參數(shù),即實際的錯誤消息:

throw new Error("Something bad happened.");

最常使用這些錯誤類型來創(chuàng)建自定義的錯誤消息:Error、RangeError、ReferenceError和 TypeError。

也可以利用原型鏈,通過繼承 Error 來創(chuàng)建自定義消息。比如,這里為新創(chuàng)建的錯誤類型指定了 name 和 message 屬性:

<script type="text/javascript">
  function CustomError(message) {
    this.name = "CustomError";
    this.message = message;
  }
  CustomError.prototype = new Error();
  throw new CustomError("My message");
</script>

這樣創(chuàng)建的自定義錯誤與瀏覽器錯誤并不同,所以可是很有用的哦O(∩_∩)O~

注意:IE 只有在拋出 Error對象時才會顯示自定義的錯誤消息!其他錯誤對象,它只會顯示 “exception thrown and not caught”。

2.1 拋出錯誤的時機

應(yīng)該在已知的、某種特定錯誤條件下(會導(dǎo)致函數(shù)無法正常執(zhí)行),拋出自定義的錯誤:

<script type="text/javascript">
  function process(values) {
    if (!(values instanceof Array)) {
      throw new Error("process():Argument must be an array.");
    }
    values.sort();
    for (var i = 0, len = values.length; i < len; i++) {
      if (values[i] > 100) {
        return values[i];
      }
    }
    return -1;
  }
  process("hi");
</script>

如果給上面的函數(shù)傳入一個字符串參數(shù),那么 sort() 就會拋錯,所以我們在這里加入了帶有適當(dāng)消息的自定義錯誤。這對于一個有著幾千行腳本代碼的項目來說,可以顯著地提升代碼的可維護性O(shè)(∩_∩)O~

錯誤消息時包含了函數(shù)名稱以及為什么會發(fā)生錯誤的明確描述,是不是很清晰呀O(∩_∩)O~

在開發(fā)時,要注意函數(shù)可能失敗的因素,把這些因素都加上自定義錯誤吧!良好的錯誤處理機制是確保代碼只發(fā)生我們定義的錯誤。

2.2 拋出錯誤與使用 try-catch

建議在拋出錯誤時盡量提供詳盡的信息,因為我們拋出錯誤不就是為了在維護時,能夠知道錯誤發(fā)生的具體位置和具體原因的嗎?

3 錯誤事件

任何沒有通過 try-catch 處理的錯誤都會觸發(fā) window 對象的 error事件(IE、Firfox 和 chrome 支持)。它接收 3 個參數(shù):錯誤消息、錯誤所在的 URL 和行號。一般只有錯誤消息有用。只能通過 DOM0 級技術(shù)來指定 onerror事件處理程序,如果返回 false,就可以阻止瀏覽器報告錯誤的默認行為:

<script type="text/javascript">
  window.onerror= function (message,url,line) {
    console.log(message);
    return false;
  }
</script>

這個函數(shù)其實就是整個文檔的 try-catch 語句,它可以捕獲所有沒有被處理的運行時錯誤。理想情況下,錯誤都被包含在 try-catch 語句中,所以不會使用到它。

注意: 不同的瀏覽器下,這個函數(shù)的處理方式不同。在 IE 中,發(fā)生了 onerror 事件,代碼仍會執(zhí)行,所有的變量和數(shù)據(jù)都會保留。但在 Firefox 中,代碼會停止執(zhí)行,而且之前所有的變量和數(shù)據(jù)都會被銷毀!

圖像也支持 error事件。如果圖像的 src 屬性中的 URL 無法返回被識別的圖像格式時,就會觸發(fā)持 error 事件。這時的 error 事件會返回一個以圖像為目標(biāo)的 event 對象:

<script type="text/javascript">
  var image = new Image();
  EventUtil.addHandler(image, "load", function (event) {
    console.log("Image loaded!");
  });
  EventUtil.addHandler(image, "error", function (event) {
    console.log("Image not loaded!");
  });
  image.src = "smilex.gif";//實際并不存在
</script>

注意,如果發(fā)生了 error事件,那么這個圖像的下載過程就已經(jīng)結(jié)束咯。

4 常見的錯誤類型

因為 JavaScript 是松散類型的語言,所以錯誤只會在代碼運行期間發(fā)生。一般情況下,我們需要重點關(guān)注以下三種錯誤:

① 類型轉(zhuǎn)換錯誤
② 數(shù)據(jù)類型錯誤
③ 通信錯誤

4.1 類型轉(zhuǎn)換錯誤

在使用相等(==)或不相等(!==),或者在 if、for 或 while 中使用了非布爾值時,最常發(fā)生類型轉(zhuǎn)換錯誤。

所以建議使用全等(===)和不全等(!==)來避免類型轉(zhuǎn)換操作。

if 等語句會自動把任何值都轉(zhuǎn)換為布爾值:

function concat(str1, str2, str3){
  var result = str1 + str2;
  if (str3){//不要這樣?。?!
    result +=str3;
  }
  return result;
}

這個函數(shù)是想拼接兩個或三個字符串,然后返回結(jié)果。所以這里的第三個參數(shù)是可選的,,所以必須要檢查。如果我們在調(diào)用這個函數(shù)時,只用到前兩個參數(shù),這意味著第三個參數(shù)因為是未使用過的命名變量,所以被自動賦值給 undefine,而 undefine 在 if 中會被自動轉(zhuǎn)換為 false,這樣可以。但是,如果第三個參數(shù)傳入數(shù)值 0,在 if 中會被自動轉(zhuǎn)換為 false,那么就不會被加到 result 中!所以我們要進行檢查:

function concat(str1, str2, str3){
  var result = str1 + str2;
  if (typeof str3 == "string"){
    result +=str3;
  }
  return result;
}

4.2 數(shù)據(jù)類型錯誤

function getQueryString(url){
  var pos = url.indexOf("?");
  if (pos > -1){
    return url.substring(pos + 1);
  }
  return "";
}

這個函數(shù)打算返回給定 URL 中的查詢字符串。但如果傳入非字符串類型的參數(shù),就會導(dǎo)致錯誤。所以要加上類型判斷:

function getQueryString(url){
  if(typeof url == "string"){
    var pos = url.indexOf("?");
    if (pos > -1){
      return url.substring(pos + 1);
    }
  }
  return "";
}

還有,如果在流控制語句中使用非布爾值也會導(dǎo)致數(shù)據(jù)類型錯誤:

function reverseSort(values){
  if (values){//非數(shù)組值都會報錯
    values.sort();
    values.reverse();
  }
}

另一種錯誤是將參數(shù)與 null 進行比較,這只能確保參數(shù)不是 null 和 undefined,也不建議將參數(shù)與 undefined 進行比較。

還有一種錯誤是,只針對某一特性進行檢測:

function reverseSort(values){
  if (typeof values.sort == "function"){
    values.sort();
    values.reverse();
  }
}

上面的函數(shù),如果傳入帶有 sort() 方法的對象,就會通過檢測,但會在調(diào)用 reverse() 方法時報錯!所以這里最好是使用 instanceof 來檢測:

function reverseSort(values){
  if (values instanceof Array){
    values.sort();
    values.reverse();
  }
}

總的來說,基本類型的值使用 typeof 檢測,而對象的值使用 instanceof 來檢測。特別是面向公眾的 API,一定要執(zhí)行類型檢查,以確保函數(shù)始終能夠正常執(zhí)行。

4.3 通信錯誤

JavaScript 與服務(wù)器之間的任何一次通信,就有可能會產(chǎn)生錯誤。

一種通信錯誤是發(fā)送了不正確的 URL 格式數(shù)據(jù)。一般是沒有使用 encodeURIComponent() 對數(shù)據(jù)進行編碼,可以使用這里的函數(shù)來處理查詢字符串:

/**
 * 添加查詢字符串
 * @param url URL
 * @param name 參數(shù)名
 * @param value 參數(shù)值
 * @returns {*}
 */
function addQueryStringArg(url, name, value) {
  if (url.indexOf("?") == -1) {
    url += "?";
  } else {
    url += "&";
  }
  url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
  return url;
}

盡量使用這個函數(shù),就可以確保編碼正確。

5 區(qū)分致命錯誤與非致命錯誤

非致命錯誤可以根據(jù)以下列出的一個或多個條件來確定:

  • 不影響用戶的主要任務(wù);
  • 只影響頁面的一部分;
  • 可以恢復(fù);
  • 重復(fù)操作可以消除錯誤。

而致命錯誤也可以根據(jù)以下列出的一個或多個條件來確定:

  • 無法繼續(xù)執(zhí)行;
  • 影響到了用戶的主要操作;
  • 導(dǎo)致其他連帶的錯誤。

如果發(fā)生了致命錯誤,要立即發(fā)送消息通知用戶,告訴他們無法再繼續(xù)操作咯。如果必須刷新頁面才會恢復(fù),也必須通知用戶,并提供了可刷新頁面的按鈕。

比如,在大型網(wǎng)站中,可能有多個互不依賴的模塊,它們是類似這樣初始化的:

for (var i=0, len=mods.length; i<len; i++){
  mods[i].init();
}

這樣做的問題是,如果有一個模塊發(fā)生錯誤,那么就會導(dǎo)致后續(xù)的其它模塊無法被初始化,從而導(dǎo)致致命的錯誤!我們這樣改造下,讓致命的錯誤變成非致命的錯誤:

for (var i=0, len=mods.length; i<len; i++){
  try{
    mods[i].init();
  } catch (ex){
    ...
  }
}

6 把錯誤記錄到服務(wù)器

建議集中保存錯誤日志,這樣可以方便后續(xù)查找錯誤的原因。所以我們可以把 JavaScript 錯誤發(fā)送給服務(wù)器,讓服務(wù)器保存起來。這樣把前后端的錯誤集中起來管理,就可以很方便地對數(shù)據(jù)進行分析咯O(∩_∩)O~

首先先在服務(wù)器上創(chuàng)建一個接口,用于接收頁面發(fā)送的錯誤數(shù)據(jù):

/**
 * 記錄 JavaScript 錯誤
 * @param sev 嚴(yán)重程度,比如:nonfatal
 * @param msg 錯誤消息
 */
function logError(sev,msg){
  var img=new Image();
  img.src="log.action?sev="+encodeURIComponent(sev)+"&msg="+encodeURIComponent(msg);
}

使用 Image 對象來發(fā)送請求,有這些好處:

  • 所有的瀏覽器都支持 Image 對象,包含那些不支持 XMLHttpRequest 對象的瀏覽器。
  • 可以避免跨域限制。比如可以使用一臺日志服務(wù)器專門接收多臺 web 服務(wù)器拋出的錯誤。

只要是使用了 try-catch 語句,就要把錯誤記錄到日志中:

for (var i=0, len=mods.length; i<len; i++){
  try{
    mods[i].init();
  } catch (ex){
    logError("nonfatal","模塊初始化失?。?+ex.message);
  }
}

第二個參數(shù)是上下文信息以及 JavaScript 的錯誤消息,帶上上下文信息可以方便分析導(dǎo)致錯誤的真正原因。

更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《JavaScript錯誤與調(diào)試技巧總結(jié)》、《JavaScript傳值操作技巧總結(jié)》、《javascript編碼操作技巧總結(jié)》、《JavaScript中json操作技巧總結(jié)》、《JavaScript切換特效與技巧總結(jié)》、《JavaScript查找算法技巧總結(jié)》、《JavaScript動畫特效與技巧匯總》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運算用法總結(jié)》

希望本文所述對大家JavaScript程序設(shè)計有所幫助。

當(dāng)前題目:JavaScript錯誤處理操作實例詳解
網(wǎng)站路徑:http://muchs.cn/article4/ihdioe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、網(wǎng)站營銷、做網(wǎng)站、用戶體驗、企業(yè)網(wǎng)站制作、App開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)