24、JavaScript错误处理与调试工具
两种处理错误方式
1、onerror事件处理函数
onerror事件处理函数是第一个用来协助JavaScript处理错误的机制。当页面上出现异常时,error事件便在window对象上触发。例如:
<html> <head> <title>OnError Example</title> <script type="text/javascript"> window.onerror = function () { alert("An error occurred."); //出错后页面上不显示错误信息。如果去掉或返回false时页面上还是会显示错误信息的 return true; } </script> </head> <body onload="nonExistentFunction()"> </body> </html>
取出错误信息
onerror事件处理函数提供了三种信息来确定错误确切的属性:
1、错误信息——对于给定错误,浏览器会显示同样的信息。
2、URL——在哪个文件中发生了错误。
3、行号——给定URL中发生错误的行号。
这个信息将作为三个参数传递给onerror事件处理函数,可以如下访问:
<html>
<head>
<title>OnError Example</title>
<script type="text/javascript">
window.onerror = function (sMessage, sUrl, sLine) {
alert("An error occurred:\n" + sMessage + "\nURL: " + sUrl + "\nLine Number: " + sLine);
return true;
}
</script>
</head>
<body onload="nonExistentFunction()">
</body>
</html>
图像载入错误
window对象并非唯一支持onerror事件处理函数的对象;图像对象也支持。当一个图像由于某原因未能成功载入时,如文件不存在时,error事件便在这个图像上触发。可以为图像设置一个onerror事件处理函数,这可以直接在HTML中设置,也可通过脚本进行设置。如:
<html>
<head>
<title>Image Error Test</title>
<script type="text/javascript">
function handleLoad() {
document.images[0].onerror = function () {
alert("An error occurred loading the image.");
};
document.images[0].src = "blue.gif";
}
</script>
</head>
<body onload="handleLoad()">
<p>The image below attempts to load a file that doesn't exist.</p>
<img />
</body>
</html>
注:与window对象的onerror事件处理函数不同,image的onerror事件处理函数没有任何关于额外信息的参数。
onerror也能处理语法错误,但一定要放在页面脚本最前。
另:
- 使用onerror事件处理函数的主要的问题是,它是BOM的一部分,所以,没有任何标准。因此,不同的浏览器使用这个事件处理函数的处理错误的方式有明显的不同。例如:在IE中发生error事件时,正常的代码会继续执行:所有的变量和数据都保留下来,并可通过onerror事件处理函数访问。然而在Mozilla中,正常的代码执行都会结束,同时所有错误发生之前的变量和数据都被销毁。
- Safari和Konqueror不支持window对象上的onerror事件处理函数,但是它们支持图像上的onerror事件处理函数。
2、try...catch语句
ECMAScript第三版,从Java中引入了另一个错误处理方法,try...catch语句。
<script type="text/javascript">
try {
window.nonExistentFunction();
alert("Method completed.");
} catch (exception) {
alert("An exception occurred.");
} finally {
alert("End of try catch test.");
}
</script>
与Java不同的是只能有一个catch子句,因为JavaScript是弱类型的语句,没有办法指明catch子句中异常的特定类型。
在finally子句中的代码与Java中的finally子句的行为一样,是否有异常都会执行。
嵌套的try...catch语句
在的try...catch语句中还可以嵌套try...catch语句。
Error对象
类似于Java有个可用于抛出的基类Exception,JavaScript有个Error基类用于抛出。Error对象有以下属性:
1、name——表示错误类型的字符串。
2、message——实际的错误信息。
Error对象的名称对应于它的类(因为Error只是一个基类),可以是以下值之一:
类 |
发生原因 |
EvalError |
错误发生在 eval() 函数中 |
RangeError |
数字的值超出 JavaScript 可表示的范围( Number.MIN_VALUE 和 Number.MAX_VALUE ) |
ReferenceError |
使用了非法的引用 |
SyntaxError |
在 eval() 函数调用中发生了语法错误,其他的语法错误由浏览器报告,无法通过 try...catch 语句处理。 |
TypeError |
变量类型不是预期所需要的 |
URIError |
在 encodeURI() 或者 decodeURI() 函数中发生了错误。 |
try { window.nonExistentFunction(); alert("Method completed."); } catch (oException) { alert("An exception occurred: " + oException.message); } finally { alert("End of try卌atch test."); }
判断错误类型
第一种方法使用Error对象的name特征:
try { eval("a ++ b"); //causes SyntaxError } catch (oException) { if (oException.name == "SyntaxError") { alert("Syntax Error: " + oException.message); } else { alert("An unexpected error occurred: " + oException.message); } }
第二种使用insanceof操作符,并使用不同错误的类名:
try { eval("a ++ b"); //causes SyntaxError } catch (oException) { if (oException instanceof SyntaxError) { alert("Syntax Error: " + oException.message); } else { alert("An unexpected error occurred: " + oException.message); } }
抛出异常
ECMAScript第三版还引入了throw语句,用于有目的地抛出异常。语法如下:
throw error_object ;
error_object可以是字符串、数字、布尔值或者是实际的对象。也可是一个Error对象,Error对象的构造函数只有一个参数,即错误信息。
throw new Error('you tried to do something bad.')
其他的Error子类也可以这样使用:
throw new SyntaxError('I don't like your syntax.');
function addTwoNumbers(a, b) { //需要二个参数 if (arguments.length < 2) { throw new Error("Two numbers are required."); } else { return a + b; } } try { result = addTwoNumbers(90); } catch (oException) { alert(oException.message); //outputs "Two numbers are required." }
- 在Firefox浏览器中,我们需要通过JavaScript控制台来查看错误信息,选择Tools | JavaScript Console即可打开JavaScript控制台。
- 在IE浏览器中,如果未安装了Script Debugger调试器,一般出错后会在浏览器左下角显示感叹号,可能还会弹出一个错误提示框,如果这些错误提示未出来,选择Tools | Internet选项 | 高级 ,把“显示每个脚本错误的通知”前打上钩即可。
调试
使用JSLint完成JavaScript语法检查
JSLint是一个JavaScript验证工具(www.jslint.com ),可以扫描JavaScript源代码来查找问题。如果JSLint发现一个问题,JSLint就会显示描述这个问题的消息,并指出错误在源代码中的大致位置。有些编码风格约定可能导致未预见的行为或错误,JSLint除了能指出这些不合理的约定,还能标志出结构方面的问题。尽管JSLint不能保证逻辑一定正确,但确实有助于发现错误,这些错误很可能导致浏览器的JavaScript引擎抛出错误。
JSLint定义了一组编码约定,这比ECMA定义的语言更为严格。这些编码约定汲取了多年来的丰富编码经验,并以一条年代久远的编程原则作为宗旨:能做并不意味着应该做。JSLint会对它认为有风险的编码实践加标志,另外还会指出哪些是明显的错误,从而促使你养成好的JavaScript编码习惯。
JSLint可能会把一些结构方面的错误标志为可疑的编码实践,以下列出了其中一部分(完整的列表可以参考JSLint的文档):
- JSLint要求所有代码行都以分号结束。尽管JavaScript确实允许将换行符作为行结束符,但一般认为这种做法是不明确的,而且是不好的编码风格。
- 使用if和for的语句必须使用大括号把语句块括起来。
- 不同于其他编程语言,在JavaScript中,块不会作为变量的作用域。JavaScript只支持函数级作用域。因此,JSLint只接受作为function、if、switch、while、for、do和try语句一部分的块,其他的块都会标志为错误。
- var只能声明一次,而且在使用之前必须声明。
- SLint会把出现在return、break、continue或throw语句后面的代码标志为不可达的代码。这些语句后面必须紧跟一个结束大括号。
对于JavaScript程序员新手来说,JSLint是一个非常好的工具,因为它会教你一些好的JavaScript编码实践。由于JSLint能把可能导致逻辑错误或其他未预见行为的部分标出来,因此可以减少调试时间。如果你调试一段JavaScript代码时遇到困难,可以试试JSLint。
Microsoft Script Debugger
打开http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn ,输入Script Debugger,可即找到。
下载后运行安装程序(后附安装包,IE7上中文安装好像出不来,装上中文后再装英文就出来了?),然后启IE。安装后注意在View菜单下会出现Script Debugger菜单。
1、运行Script Debugger
可以以多种方式运行Script Debugger。
首先,可以直接通过选择 View—>Script Debugger—>Open,打开没有载入任何信息的调试器。
注:如果在 View 菜单下看不到 Script Debugger 子菜单时,请检查以下选项是否打开或关闭:
第二种,运行时出错自动打开。
编写如下页面代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script language="JavaScript" type="text/javascript">
function writeTimesTable(timesTable) {
var counter;
var writeString;
for (counter = 1; counter < 12; counter++) {
writeString = counter + " * " + timesTable + " = ";
writeString = writeString + (timesTable * counter);
writeString = writeString + "<br>";
documents.write(writeString);//document写错了
}
}
</script>
</head>
<body>
<div>
<script language=JavaScript type="text/javascript">
writeTimesTable(2)
</script>
</div>
</body>
</html>
运行出现如下调试对话框:
点击是,由于选择了对代码进行调试,你将看到一个如下图所示的窗口。脚本调试器已经被打开,代码的执行在出现错误的代码行上被停止,并且该行代码将以黄颜色突出显示。在上面代码中的最后一行,我们故意将document.write错误地拼写为documents.write,因此错误代码行将被突出显示。在调试器的窗口中,代码是只读的,因此并不能在调试器的窗口中对代码进行编辑。需要返回到文本编辑器中,才能修改代码中的错误。在文本编辑器中修正代码后,在浏览器中重新加载该页面。
第三种方式:当在浏览器中加载完页面,可以选择IE浏览器的View | Script Debugger | Break at Next Statement。浏览器此时并没有什么反应,这是为下一次运行做准备的,此时只要再单击浏览器的 刷新 图标或者按F5键,脚本调试器将在JavaScript执行的下一条语句上打开。
JavaScript将要执行的下一条语句取决于所编写的代码。除了函数或者连接到事件处理器的代码外,如果页面中还有其他的JavaScript代码,则JavaScript将要执行的下一条语句就是浏览器执行的第一条JavaScript语句。在上面的例子中,就是调用了writeTimesTable(2)函数的语句:
<script>writeTimesTable(2)</script>
如果除了事件处理器中的代码之外,页面中并不包含其他的JavaScript代码,则JavaScript将要执行的下一条语句将是由一个事件处理器所触发的代码,例如由window对象的onload事件处理器,或者按钮的onclick事件处理器所触发的代码。
由于脚本调试器的构成,浏览器弹出的“Runtime Error(运行时错误)”类型的异常将不会被处理。但这并不意味着代码中没有错误,我们只需简单地使用Break at Next Statement菜单项来进行处理即可。
在上面的例子中,JavaScript将要执行的下一条语句就是浏览器解析到的嵌入在页面中的调用writeTimesTable()函数的语句。另外,调用writeTimesTable()函数的那条语句已经被脚本调试器以黄颜色突出显示。
第四种,还可在代码的任意位置使用JavaScript的debugger 命令来找开调试器,如:
var iSum = 1 + 2; debugger;//启动调试程序窗口 var iProduct = iSum * 10;
代码遇到debugger命令时,代码执行被中断,并打开调试器(与 Break At Next Statement选项的功能很像)。
2、窗口
Microsoft Script Debugger 由一个窗口和三个小的工具窗口组成。
标题为Running Document窗口
:显示所有正在运行的IEEE的实例,以及在每个实例中载入的文档。通过点开加号,可以看到会不止一个HTML文件被载入,还有它所依赖的JavaScript文件。然后可以打开这些文件进行相应的调试。
标题为Call Stack窗口 :代码当前断点的调用堆栈。双击此窗口中的某个条目则可以得到这个函数的源代码。
标题为Command Window窗口 :这里,可在正在执行的代码的上下文中输入JavaScript命令来来检查变量的值。只要在其中输入需要查看的变量的名称,并以分号结尾,回车就会输出其值。
3、断点与单步调试
要在代码中设置断点,在IE载入文件,然后打开调试器。在Running Documents窗口中找到要高度的文件并打开它。然后,找到要在哪一行上停止,按F9设置断点。然后,重新载入页面,代码会在指定的位置停止执行,这时调试器接手工作。这时,你可做这些事情:
- 如果想单步调试代码,可使用Step Into(按照代码的顺序逐行执行,在每一行之后停止),Step Over(不会进入函数中执行)和Step Out(将执行点移动到函数被调用的位置,即跳出函数);
- 如果要继续正常的代码执行,点Running按钮,但代码会在下个断点处停止;
- 如果要完全停止调试,点击Stop Debugger按钮,接下来任何代码的执行都不会停止。