While debugging some client side javascript today in Firefox, I ran into something that I found quite odd and little unnerving. Also, I was unable to duplicate this behavior wh
$.get("http://google.com/")
is asynchronous, it is a race on what gets done first. The first time it is slower since it needs to make the call and the call happens later in the code execution. The call is already cached with the second request, so it happens to execute quicker.
If you need something to be done before the request goes out use beforeSend().
To my experience, Firebug doesn't work well when putting breakpoints in asynchronous code.
I.e. if you have one straight line of execution and put breakpoints in it, you'll be fine. However if you introduce asynchronicity e.g. by using setTimeout
, you won't hit the breakpoint in that "parallel" line (which of course is not parallel really, the JS engine switches between the tasks). I've been experiencing it a lot in last couple of months.
In Chrome, it seems to work fine (they defer timeouts intelligently somehow). Perhaps because Chrome dev tools are built-in to the browser, it's easier to manipulate the timeouts. Firebug is "just" an add-on and perhaps it may be tricky to do it correctly.
A simple script to reproduce the issue:
Put breakpoints in lines when I assign value to x
, y
, z
.
First, you'll hit a breakpoint on the line x = 1
. Use F10 to step over. You won't hit a breakpoint on the line with will hit a breakpoint on the line with z = 3
everz = 3
only if you're quick enough with pressing F10 (Firefox 14, Firebug 1.10).
<!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>
I think it's safe to assume that the anomaly you're observing is caused by how Firebug implements breakpoints/works under the hood. I can't confirm that though. This also happens with FF 14 on OS X.
Unless jQuery immediately executes your fail()
function and surpasses the whole XMLHttpRequest
object, then there is a guarantee that the ordering of the statements will be this will probably happen first.
then this will probably happen second.
.
Given the single threaded nature of JavaScript, functions will be essentially atomic; they will not get interrupted by a callback.
It seems as though you're trying to simulate what would happen if the click
function takes a while to finish executing after calling loadStuff()
. The click
function shouldn't get interrupted by the fail
method executing (mind == blown that you found a way to make that happen).
To take breakpoints out of the equation, here's a modified version. The rest of the markup is unchanged.
$(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.");
});
}
The click
function clearly takes a long time to execute, after calling loadStuff()
, but the console will still reflect the correct order of the log statements here. Also worth noting, if you insert the same breakpoints, the ordering will be invalid, like the original example.
I'd file an issue for this with Firebug.