今天在Firefox中调试一些客户端javascript时,我遇到了一些奇怪且有点令人不安的事情。此外,在使用IE/VS2010调试同一脚本时,我无法复制此行为。
我创建了一个简单的html文档示例来说明我所看到的异常情况。
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js" type="text/javascript" ></script>
</head>
<body id="main_body">
<script type="text/javascript">
$(function () {
$(".test-trigger").on("click", function () {
loadStuff();
console && console.log && console.log("this will probably happen first.");
});
});
function loadStuff() {
$.get("http://google.com/")
.fail(function () {
console && console.log && console.log("this will probably happen second.");
});
}
</script>
<button class="test-trigger">test</button>
</body>
</html>
如果你将此文档加载到Firefox中(我在Windows 7上使用的是13.0版本和1.10.1版本的Firebug),点击测试,并在Firebug中查看控制台选项卡,你应该注意到get请求失败了(跨域违规与我在这里试图提出的观点无关),然后你很可能会看到:
this will probably happen first.
this will probably happen second.
现在,在第13行和第20行放置断点:
13: console && console.log && console.log("this will probably happen first.");
20: console && console.log && console.log("this will probably happen second.");
如果您再次单击"测试",您将按预期在第13行中断。现在,继续执行。如果你的经验和我一样,你就不会在20号线上崩溃。此外,如果您切换到控制台选项卡,您将看到以下日志输出序列:
this will probably happen second.
this will probably happen first.
对我来说,这表明ajax请求的失败处理程序是在一个线程中执行的,而不是在点击处理程序中执行的。我一直相信,在任何浏览器中,单个页面的所有javascript都将由单个线程执行。我是不是错过了一些显而易见的东西?感谢您对这一观察的任何见解。
哦,如果我使用Visual Studio调试在IE中运行的同一个页面,两个断点都会像我预期的那样被命中。
我认为可以安全地假设您观察到的异常是由Firebug如何在后台实现断点/工作引起的。不过我不能证实。这也发生在操作系统X上的FF 14上。
除非jQuery立即执行fail()
函数并超越整个XMLHttpRequest
对象,否则可以保证语句的顺序是this will probably happen first.
然后是this will probably happen second.
。
考虑到JavaScript的单线程性质,函数本质上将是原子的;它们不会被回调所打断。
似乎您正在尝试模拟如果click
函数在调用loadStuff()
后需要一段时间才能完成执行,会发生什么。click
函数不应该被fail
方法的执行所中断(记住你找到了实现这一点的方法)。
为了去掉等式中的断点,这里有一个修改后的版本。标记的其余部分保持不变。
$(function () {
$(".test-trigger").on("click", function () {
loadStuff();
for (var i = 0; i < 1000000000; i++)
{
//block for some interesting calculation or something
}
console && console.log && console.log("this will probably happen first.");
});
});
function loadStuff() {
$.get("http://google.com/")
.fail(function () {
console && console.log && console.log("this will probably happen second.");
});
}
调用loadStuff()
后,click
函数显然需要很长时间才能执行,但控制台仍会在此处反映日志语句的正确顺序。同样值得注意的是,如果插入相同的断点,则排序将无效,就像最初的示例一样。
我会向Firebug提交一个问题。
$.get("http://google.com/")
是异步的,它是一场关于先完成什么的竞赛。第一次它的速度较慢,因为它需要进行调用,而调用发生在代码执行的后期。该调用已经与第二个请求一起缓存,因此它的执行速度更快。
如果在请求发出之前需要做一些事情,请使用beforeEnd()。
根据我的经验,在异步代码中设置断点时,Firebug不能很好地工作。
也就是说,如果你有一条直线执行,并在其中设置断点,你就可以了。然而,如果引入异步性,例如使用setTimeout
,则不会在"并行"行中遇到断点(当然,这实际上不是并行的,JS引擎在任务之间切换)。在过去的几个月里,我经历了很多。
在Chrome中,它似乎运行良好(它们以某种方式智能地推迟超时)。也许是因为浏览器内置了Chrome开发工具,所以操作超时更容易。Firebug"只是"一个附加组件,也许要正确执行它可能很棘手。
一个简单的脚本来重现问题:
当我为x
、y
、z
赋值时,在行中放置断点。首先,您将在x = 1
行上遇到一个断点。使用F10进行跨步操作。您不会在带有只有在您足够快地按下F10(Firefox 14,Firebug 1.10)时才会在带有z = 3
的行上遇到断点,z = 3
的行上碰到断点。
<!DOCTYPE html>
<html>
<body>
<script type="text/javascript">
function foo(){
var x = 1;
setTimeout(bar, 2000);
var y = 2;
}
function bar(){
var z = 3;
}
foo();
</script>
</body>
</html>