<html> <head> <title>Javascript Debugging</title> <script> function populateDiv(){ var divElement = document.getElementById('messageLabel'); divElement.innerHTML = "Lorem ipsum dollor"; } </script> </head> <body> <div id="messageLabel"></div> <input type="button" value="Click Me!" onclick="populateDiv();" /> </body> </html>
在本章里,我们将讨论Firebug提供的,以支持JavaScript的开发、调试、概览、以及测试的各种工具。在这里我们将采用典型的
JavaScript用例的方式,并解释如何使用Firebug来实现这些用例。
在本章里,我们将讨论以下主题:
在第2章“Firebug窗口概览”中,我们已经看到了如何使用命令行,这里,我们将讨论的是命令行API提供的一些方法(methods)。这些方法将帮助我们调试JavaScript。下面是具体的描述与用法:
这个方法类似于JavaScript中的document.getElementById()。它返回指定ID的单个元素。
我们将使用下面的HTML代码来解释$(id)方法。将这些代码写在一个HTML文件中,并用Firefox将其打开。
<html> <body> <input name="myText" id="test_id" type="text"> </body> </html>
现在,当我们在Firebug的命令行中执行如下代码,我们将看见如下的输出窗口:
$("test_id")
这个方法返回由指定CSS选择器匹配元素所组成的数组。
下面的HTML代码片段显示在其DOM树上有四个<input>HTML元素。我们将使用$$(选择器)的方法来选择全部四个元素:
<html> <body> <input name="myText1" type="text" class="test_class" > <input name="myText2" type="text" class="test_class" > <input name="myText3" type="text" class="test_class" > <input name="myText4" type="text" class="test_class" > </body> </html>
下面的截图显示了在Firebug的命令行中执行 $$('input') 之后的输出结果:
此方法返回与给定的XPath表达式相匹配的元素的数组。
为了解释此方法,我们将使用前面的HTML文件来讲解。现在,当我们在Firebug命令行执行如下代码,我们将在Firebug的控制台标签页看到输出结果:
var objs = $x('html/body/input') console.log(objs[0].name) console.log(objs[1].name) console.log(objs[3].name) console.log(objs[3].name)
这个方法打印出对象的所有属性的交互清单。这个结果与我们在DOM标签页内看到的是一致的。
让我们来看一下与我们在$$(选择器)方法中使用过的HTML代码。如果我们在Firebug的命令行中执行下面的代码,我们将会得到如下的输出:
var objs = $x('html/body/input') dir(objs)
这个方法将打印一个HTML或XML元素的XML源码树。这个结果与我们在HTML标签页内看到的结果是一致的。我们可以在HTML标签页内点击任意节点来观察它。
使用相同的HTML文件,在Firebug的代码行中执行如下代码将得到其XML源码树。下面的截图显示了在控制台标签页内产生的输出结果:
var obj = $$('body')[0] dirxml(obj)
我们可以用$(id)选择一个节点后,再将其传递给此方法,或者采用与此类似的其他获取一个节点的方法。
默认情况下,命令行表达式是与页面的顶层窗口相关的。cd()方法将使我们可以使用页面内的框架窗口。
这个方法将对控制台清屏。此方法提供的功能也可以通过点击“清除”按钮实现,这个按钮在控制台标签页的左上角。
这个方法让我们可以用最适合的标签来检查一个对象,或者使用与可选参数tabName相一致的标签。
可以使用的标签名字有HTML、CSS、SCRIPT,以及DOM。
现在,对我们已经打开的HTML文档,我们在Firebug的命令行中输入下面代码。输出结果将显示在HTML标签页内,截图如下:
inspect($$('input')[0], 'html')
这个方法返回一个包含此对象所有属性的名字的数组。
还是使用我们前面使用的HTML文件为例,执行下面的代码将显示第一个input标签的全部属性、实体、函数和常量:
keys($$('input')[0])
这个方法将返回一个包含该对象所有属性值的数组。
执行下面的代码将显示DOM树中第一个input标签的所有属性值。
values($$('input')[0])
这两个方法将在函数的第一行增加或移除断点。
我们将在后面第8章“AJAX开发”中学习这些方法的细节内容。
这些方法被用来打开或关闭对一个函数所有调用的日志记录。
通常,为了查看JavaScript中某个函数是否被调用,我们在其内部设置alert()或console.log()方法。这是非常繁琐的事情。首先,我们不得不在一个大的JavaScript文件中找到这个方法,然后我们需要添加alert或log方法。接下来,当我们看到每样事情都对了,我们需要从代码中移除所有的这些日志声明。
Firebug用巧妙的方式来处理这种监视工作。为了判断某个函数是否被调用,我们仅仅需要知道函数的名字就可以了。通过使用monitor()方法,我们可以跟踪发现该函数被调用了多少次。我们将在控制台上看到提示,告诉我们正在被监视的函数是否被调用了。并且,它还会给我们一个指向函数脚本的链接。
我们以下面的代码为例来进行讨论,创建一个HTML文件,输入以下代码,并且用Firefox浏览器打开这个文件:
<html> <script> function function1(){ return true; //some statement } function function2(){ return true; //some statement } </script> <body> This is the body <input id="button1" type="button" value="Invoke function1()" onclick="function1();" /> <input id="button2" type="button" value="Invoke function2()" onclick="function2();" /> <input id="button3" type="button" value="Invoke function3()" onclick="function3();" /> </body> </html>;
现在,在命令行输入下面的代码并且执行:
monitor(function1)
点击本文档中的按钮“Invoke function1()”。我们将看到,无论何时只要调用了一次function1()函数,Firebug就会在控制台面板上显示其日志记录。如果我们在控制台面板上点击function1()的链接,将跳转到function1()函数所在的行。
下面的代码将取消对function1()函数的监控:
unmonitor(function1)
此方法将开启对发送到一个对象的所有事件的日志记录。可选的参数类型指定只记录特定的消息族。类型中最常使用的值是mouse和key。
全部可用类型包括:composition, context menu, drag, focus, form, key, load, mouse, mutation, paint, scroll, text, ui, 以及 xul。
此方法关掉发送到某对象的所有事件的日志记录。
监视和取消监视事件与日志事件是一样的,关于日志事件我们已经在前一章讨论过。
让我们考察全面使用的HTML文件。在命令行执行下面的代码并且点击第一个按钮:
monitorEvents($("button1"))
下面的截图显示了事件监控情况:
这两个方法用于开启和关闭JavaScript概况器。可选参数title将作为概况报告的抬头打印在文本中。
下面是在Firebug中启动JavaScript概况器的三个方法:
为查看概况器产生的统计信息,输入如下HTML代码,并保存为HTML文件,然后在浏览器中打开此文件。按F12打开Firebug并且点击“Start”按钮。
<html> <head> <title>Firebug</title> <script> function bar(){ console.profile('Measuring time'); foo(); console.profileEnd(); } function foo(){ loop(1000); loop(100000); loop(10000); } function loop(count){ for(var i=0; i<count; i++){} } </script> </head> <body> Click this button to profile JavaScript <input type="button" value="Start" onclick="bar();" /> </body> </html>
下面截图显示了概况器产生的统计信息:
平均时间=自身代码执行时间 / 调用次数
Firebug对所有加载的页面增加了一个全局变量,命名为“console”。这个对象包括许多方法,这些方法使得我们可以向控制台写入信息,以揭示出脚本运行中的信息。
这个方法向控制台写入一个消息。我们可以传递任意多的参数,这些参数在一个空格分隔行内被链接起来。
log的第一个参数也许是包含类似printf字符串替换模式的字符串。例如:
console.log("The %s jumped over %d tall buildings", animal, count);
上面的例子可以用非字串替换的方式来重写,效果一样:
console.log("The", animal, "jumped over", count, "tall buildings");
这两个技术可以联合起来用。如果我们使用字符串替换模式,但是给出的参数多过替换模式使用的参数,其余的参数将附加在空格分隔行内,如下面的代码所示:
console.log("I am %s and I have:", myName, thing1, thing2, thing3);
如果对对象进行了日志记录,这些对象显示出来的就不止是静态文本,还有交互式的超链接,这些链接分别指向Firebug中与该对象相关的HTML、CSS、脚本或DOM标签页。我们也可以使用%o的模式在字符串中替换超链接。
下面是我们可以使用的字符串替代的全部模式:
Table�1.1.�
字符串
替换模式
%s
字符串
%d, %i
整数(还不支持格式化的数值)
%f
浮点数(还不支持格式化的数值)
%o
对象链接
此方法把一个消息写到控制台,这个消息包括了指向此方法被调用的行的超链接。
此方法向控制台写入一个消息,这个消息带有可视化的信息图标(info icon)、作色代码、以及指向此方法被调用的行的超链接。
此方法向控制台写入一个消息,这个消息带有可视化的警告图标、作色代码、以及指向此方法被调用的行的超链接。
此方法向控制台写入一个消息,这个消息带有可视化的错误图标(error icon)、作色代码、以及指向此方法被调用的行的超链接。
此方法测试一个表达式是否为真,如果不是,它将向控制台写入一个消息,并抛出异常。
此方法打印出对象的所有属性的交互式列表。看起来与我们在DOM标签页中看到的视图是一致的。
此方法打印HTML或XML元素的XML源代码树。这与我们在HTML标签页中看到的是一致的。我们可以通过点击节点在HTML标签页内检查此节点。
此方法输出Javascript代码在被调用时所执行交互式栈的跟踪。
这个栈跟踪列出了栈中的函数细节,以及每一个传递给函数的参数值。通过点击函数,将转到脚本标签页内相应代码的位置。并且,点击参数值将可以查看其在DOM或HTML标签页中的情况。
此方法想控制台写入一个消息,并且以后向此控制台写入的消息都被缩进的嵌入一个块中。调用console.groupEnd()可以关闭这个块。
这个方法类似于console.group(),只不过这个块最初是折叠的。
此方法关闭被console.group()或console.groupEnd()最近打开的块。
此方法用给定的名字创建一个新的计时器。用相同的名字调用console.timeEnd(名字)将停止计时器并且打印出所耗用的时间。
此方法终止console.time(name)所创建的定时器,并打印出消耗的时间。
此方法启用JavaScript概写器。作为可选项的参数将会出现在概写报告的头部。
此方法将关闭JavaScript概写器并打印出报告。
此方法将返回count被调用的代码行的执行时间。作为可选参数的标题,将会在count所在行增加一个消息输出。
本节介绍使用Firebug如果在内部和外部调试JavaScript。在开始之前,先回忆一下前面章节所介绍的内容:
使用Mozilla的Firefox和Firebug来调试JavaScript是一个非常直观的过程。如果我们是Visual Studio的开发者,我们将不会感到使用Firebug来调试JavaScript有什么不同,除了调试器是作为浏览器的一部分之外。
在一个编辑器中输入下列代码,并保存为.html文件,然后使用Firefox打开它:
<html> <head> <title>Javascript Debugging</title> <script> function populateDiv(){ var divElement = document.getElementById('messageLabel'); divElement.innerHTML = "Lorem ipsum dollor"; } </script> </head> <body> <div id="messageLabel"></div> <input type="button" value="Click Me!" onclick="populateDiv();" /> </body> </html>
现在在浏览器中按F12来打开并激活Firebug。点击“脚本”标签页,并在第6行插入断点,如下面的截图所示:
在第6行显示一个大的红点,表明这里插入了一个断点。现在,点击“Click Me!”按钮来执行JavaScript代码。
一旦我们点击,JavaScript将停在第6行,断点所在的地方。
现在我们可以单步调试JavaScript,通过点击在脚本标签页下的这些按钮来操作:继续、单步进入、单步跳过、单步退出。
现在,我们点击“单步跳过”并按F10执行第6行并移动到第7行。注意右边的“监控”面板中的divElement的值。在执行第6行之前该值是undefined,在执行第6行之后,它被赋予一个HTML的div元素作为值。让我们来看下面的截图:
如果我们想要看看调用及执行流的栈的情况,只需要点击在脚本标签页的右边点击“堆栈”标签。