第17章 錯(cuò)誤處理與調(diào)試
1. 瀏覽器報(bào)告的錯(cuò)誤
2. 錯(cuò)誤處理
(1) try-catch語(yǔ)句
try {
window.someNonexistentFunction();
} catch (error){
alert(error.message);
}
*finally 子句
只要代碼中包含 finally 子句,則無(wú)論 try 或 catch 語(yǔ)句塊中包
含什么代碼——甚至 return 語(yǔ)句,都不會(huì)阻止 finally 子句的執(zhí)行。
*錯(cuò)誤類型
-
Error是基類型,其他錯(cuò)誤類型都繼承自該類型。 -
EvalError 類型的錯(cuò)誤會(huì)在使用 eval()函數(shù)而發(fā)生異常時(shí)被拋出。 -
RangeError 類型的錯(cuò)誤會(huì)在數(shù)值超出相應(yīng)范圍時(shí)觸發(fā)。 -
ReferenceError類型找不到對(duì)象的情況下拋出。
5.syntaxError,當(dāng)我們把語(yǔ)法錯(cuò)誤的 JavaScript 字符串傳入 eval()函數(shù)時(shí),就會(huì)導(dǎo)致此類錯(cuò)誤。 -
TypeError 類型在 JavaScript 中會(huì)經(jīng)常用到,在變量中保存著意外的類型時(shí),或者在訪問(wèn)不存在的 方法時(shí),都會(huì)導(dǎo)致這種錯(cuò)誤。錯(cuò)誤的原因雖然多種多樣,但歸根結(jié)底還是由于在執(zhí)行特定于類型的操作 時(shí),變量的類型并不符合要求所致。
7.URIError在使用 encodeURI()或 decodeURI(),而 URI 格式不正確時(shí),就會(huì)導(dǎo)致 URIError 錯(cuò)誤。
(2) 拋出錯(cuò)誤
- 與 try-catch 語(yǔ)句相配的還有一個(gè)
throw 操作符,用于隨時(shí)拋出自定義錯(cuò)誤。拋出錯(cuò)誤時(shí),必須要給 throw 操作符指定一個(gè)值,這個(gè)值是什么類型,沒(méi)有要求。 - 在遇到 throw 操作符時(shí),代碼會(huì)立即停止執(zhí)行。僅當(dāng)有 try-catch 語(yǔ)句捕獲到被拋出的值時(shí),代 碼才會(huì)繼續(xù)執(zhí)行
throw new SyntaxError("I don’t like your syntax.");
throw new TypeError("What type of variable do you take me for?"); throw new RangeError("Sorry, you just don’t have the range.");
throw new EvalError("That doesn’t evaluate.");
throw new URIError("Uri, is that you?");
throw new ReferenceError("You didn’t cite your references properly.");
- 利用原型鏈還可以通過(guò)繼承 Error 來(lái)創(chuàng)建
自定義錯(cuò)誤類型。
function CustomError(message){
this.name = "CustomError";
this.message = message;
}
CustomError.prototype = new Error();
throw new CustomError("My message");
*拋出錯(cuò)誤的時(shí)機(jī)
應(yīng)該在出現(xiàn)某 種特定的已知錯(cuò)誤條件,導(dǎo)致函數(shù)無(wú)法正常執(zhí)行時(shí)拋出錯(cuò)誤。
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;
}
(3) 錯(cuò)誤(error)事件
任何沒(méi)有通過(guò) try-catch 處理的錯(cuò)誤都會(huì)觸發(fā) window 對(duì)象的 error 事件。
1.在任何 Web 瀏覽器中,onerror 事件處理程序都不會(huì)創(chuàng)建 event 對(duì)象, 但它可以接收三個(gè)參數(shù):錯(cuò)誤消息、錯(cuò)誤所在的 URL 和行號(hào)。
2.要指定 onerror 事件處理程序,必須使用如下所示的DOM0 級(jí)技術(shù),它沒(méi)有遵循“DOM2 級(jí) 事件”的標(biāo)準(zhǔn)格式。
- 在事件處理程序中返回 false,可以阻止瀏覽器報(bào)告錯(cuò)誤的默認(rèn)行為。
window.onerror = function(message, url, line){
alert(message);
return false;
};
- 圖像也支持 error 事件。只要圖像的 src 特性中的 URL 不能返回可以被識(shí)別的圖像格式,就會(huì)觸 發(fā) error 事件。
var image = new Image();
EventUtil.addHandler(image, "load", function(event){
alert("Image loaded!");
});
EventUtil.addHandler(image, "error", function(event){
alert("Image not loaded!");
});
image.src = "smilex.gif"; //指定不存在的文件
(4) 處理錯(cuò)誤的策略
(5) 常見(jiàn)的錯(cuò)誤類型
*類型轉(zhuǎn)換錯(cuò)誤
類型轉(zhuǎn)換錯(cuò)誤發(fā)生在使用某個(gè)操作符,或者使用其他可能會(huì)自動(dòng)轉(zhuǎn)換值的數(shù)據(jù)類型的語(yǔ)言結(jié)構(gòu)時(shí)。
在使用相等(==)和不相等(!=)操作符,或者在 if、for 及 while 等流控制語(yǔ)句中使用非布爾值時(shí), 最常發(fā)生類型轉(zhuǎn)換錯(cuò)誤。
*數(shù)據(jù)類型錯(cuò)誤
*通信錯(cuò)誤
- 第一種通信錯(cuò)誤與格式不正確的 URL 或發(fā)送的數(shù)據(jù)有關(guān)。最常見(jiàn)的問(wèn)題是在將數(shù)據(jù)發(fā)送給服務(wù)器 之前,沒(méi)有使用 encodeURIComponent()對(duì)數(shù)據(jù)進(jìn)行編碼。
(6) 區(qū)分致命錯(cuò)誤和非致命錯(cuò)誤
- 非致命錯(cuò)誤:
- 不影響用戶的主要任務(wù);
- 只影響頁(yè)面的一部分;
- 可以恢復(fù);
- 重復(fù)相同操作可以消除錯(cuò)誤。
- 致命錯(cuò)誤:
- 應(yīng)用程序根本無(wú)法繼續(xù)運(yùn)行;
- 錯(cuò)誤明顯影響到了用戶的主要操作;
- 會(huì)導(dǎo)致其他連帶錯(cuò)誤。
(7) 把錯(cuò)誤記錄到服務(wù)器
3. 調(diào)試技術(shù)
(1) 將消息記錄到控制臺(tái)
- 通過(guò)
console 對(duì)象向 JavaScript 控制臺(tái)中寫(xiě)入消息,這個(gè)對(duì)象具有下列方法:
- error(message):將錯(cuò)誤消息記錄到控制臺(tái)
- info(message):將信息性消息記錄到控制臺(tái)
- log(message):將一般消息記錄到控制臺(tái)
- warn(message):將警告消息記錄到控制臺(tái)
- 通過(guò)
opera.postError()方法來(lái)訪問(wèn)。這個(gè)方法 接受一個(gè)參數(shù),即要寫(xiě)入到控制臺(tái)中的參數(shù)。 - 在 JavaScript 中運(yùn)行 Java 代碼。
function log(message){
if (typeof console == "object"){
console.log(message);
} else if (typeof opera == "object"){
opera.postError(message);
} else if (typeof java == "object" && typeof java.lang == "object"){
java.lang.System.out.println(message);
}
}
function sum(num1, num2){
log("Entering sum(), arguments are " + num1 + "," + num2);
log("Before calculation");
var result = num1 + num2;
log("After calculation");
log("Exiting sum()");
return result;
}
(2) 將消息記錄到當(dāng)前頁(yè)面
在頁(yè)面中開(kāi)辟一小塊區(qū)域,用以顯示消息。這個(gè)區(qū)域通常是一個(gè) 元素,而該元素可以總是出現(xiàn)在頁(yè)面中,但僅用于調(diào)試目的;也可以是一個(gè)根據(jù)需要?jiǎng)討B(tài)創(chuàng)建的元素。
function log(message){
var console = document.getElementById("debuginfo");
if (console === null){
console = document.createElement("div");
console.id = "debuginfo";
console.style.background = "#dedede";
console.style.border = "1px solid silver";
console.style.padding = "5px";
console.style.width = "400px";
console.style.position = "absolute";
console.style.right = "0px";
console.style.top = "0px";
document.body.appendChild(console);
}
console.innerHTML += "<p>" + message + "</p>";
}
(3) 拋出錯(cuò)誤
對(duì)于大型應(yīng)用程序來(lái)說(shuō),自定義的錯(cuò)誤通常都使用
assert()函數(shù)拋出。這個(gè)函數(shù)接受兩個(gè)參數(shù), 一個(gè)是求值結(jié)果應(yīng)該為 true 的條件,另一個(gè)是條件為 false 時(shí)要拋出的錯(cuò)誤。
function assert(condition, message){
if (!condition){
throw new Error(message);
}
}
function divide(num1, num2){
assert(typeof num1 == "number" && typeof num2 == "number",
"divide(): Both arguments must be numbers.");
return num1 / num2;
}
4.常見(jiàn)的 IE 錯(cuò)誤
(1) 操作終止
操作終止: 在修改尚未加載完成的頁(yè)面時(shí),就會(huì)發(fā)生操作終止錯(cuò)誤。發(fā)生錯(cuò)誤時(shí), 會(huì)出現(xiàn)一個(gè)模態(tài)對(duì)話框,告訴你“操作終止?!眴螕舸_定(OK)按鈕,則卸載整個(gè)頁(yè)面,繼而顯示一張 空白屏幕。
當(dāng)<script>節(jié)點(diǎn)被包含在某個(gè)元素中, 而且 JavaScript 代碼又要使用 appendChild()、innerHTML 或其他 DOM 方法修改該元素的父元素或 祖先元素時(shí),將會(huì)發(fā)生操作終止錯(cuò)誤(因?yàn)橹荒苄薷囊呀?jīng)加載完畢的元素)。
(2) 無(wú)效字符
所謂無(wú)效字符,就是 JavaScript 語(yǔ)法中未定義的字符。
(3) 未找到成員
如果在對(duì)象被銷毀之后,又給該對(duì)象賦值,就會(huì)導(dǎo)致未找到成員錯(cuò)誤。而導(dǎo)致這個(gè)錯(cuò)誤 的,一定是 COM 對(duì)象。發(fā)生這個(gè)錯(cuò)誤的最常見(jiàn)情形是使用 event 對(duì)象的時(shí)候。IE 中的 event 對(duì)象是 window 的屬性,該對(duì)象在事件發(fā)生時(shí)創(chuàng)建,在最后一個(gè)事件處理程序執(zhí)行完畢后銷毀。假設(shè)你在一個(gè) 閉包中使用了 event 對(duì)象,而該閉包不會(huì)立即執(zhí)行,那么在將來(lái)調(diào)用它并給 event 的屬性賦值時(shí),就 會(huì)導(dǎo)致未找到成員錯(cuò)誤。
(4) 未知運(yùn)行時(shí)錯(cuò)誤
當(dāng)使用 innerHTML 或 outerHTML 以下列方式指定 HTML 時(shí),就會(huì)發(fā)生未知運(yùn)行時(shí)錯(cuò)誤(Unknown runtime error):一是把塊元素插入到行內(nèi)元素時(shí),二是訪問(wèn)表格任意部分(<table>、<tbody>等)的 任意屬性時(shí)。
(5) 語(yǔ)法錯(cuò)誤
如果你引用了外部的 JavaScript 文件,而該文件最終并沒(méi)有返回 JavaScript 代碼,IE 也會(huì)拋出語(yǔ)法 錯(cuò)誤。例如,<script>元素的 src 特性指向了一個(gè) HTML 文件,就會(huì)導(dǎo)致語(yǔ)法錯(cuò)誤。
(6) 系統(tǒng)無(wú)法找到指定資源
在使用 JavaScript 請(qǐng)求某個(gè)資源 URL,而該 URL 的長(zhǎng)度超過(guò)了 IE 對(duì) URL 最長(zhǎng)不能超過(guò) 2083 個(gè)字符的限制時(shí),就會(huì)發(fā)生這個(gè)錯(cuò)誤。