1

This is in Firefox 4 (4.0.1); The order of alerts is "as expected" in Firefox 3 (Firefox 3.6.17), IE 9 (9.0.8112.16421), and Chrome 11 (11.0.696.68).

The expected order of alerts is "Now", "Wait-End(x)", "End(x)", where x is some number that is the same.

However, the observed order is "Now", "End(0)", "Wait-End(x)". Why does setTimeout not run asynchronously after the while? This seems like it could be very problematic, as shown with the counter. Here is the jsfiddle for the following test case:

function doLater(callback) {
    // if the timeout is larger than about 800ms it "works as expected"
    setTimeout(callback, 1)
    alert("Now")
}

var waiting = 0;
doLater(function () { alert("End(" + waiting + ")") })
var end = (+new Date) + 2000
while ((+new Date) < end) { waiting++ }
alert("Wait-End(" + waiting + ")")

If the timer timeout is above ~800ms then the expected behavior occurs. (Timeouts of 100ms and 500ms still exhibit the unexpected order).

It really seems like a bug.


Update: This partially a Heisenberg. The following works as expected. It appears that alert in Firefox 4.0.1 will process pending events (when closed?). The jsfiddle and code:

function doLater(callback) {
    setTimeout(callback, 1)
    console.log("Now")
}

var waiting = 0;
doLater(function () { console.log("End(" + waiting + ")") })
var end = (+new Date) + 2000
while ((+new Date) < end) { waiting++ }
console.log("Wait-End(" + waiting + ")")

With this new information, does Firefox 4's alert behavior still operate within applicable Javascript / event-model specifications? In particular, the code which invoked the alert is still "active" but the effect is that it is being momentarily preempted with event processing.

  • I checked the fiddle; the alerts show in the proper order in Firefox 3.6.17. It's odd that the execution order changed across versions... But to the best of my understanding, there never was any guarantee of your functions running in the "right" order to begin with (since they're all asynchronous). – DavidJCobb May 21 '11 at 21:02
  • @DavidJCobb Thanks for the report on Firefox 3.6. I was under the impression the order was guaranteed; that is, an asynchronous event *can't preempt* currently executing Javascript. –  May 21 '11 at 21:09
  • 1
    Regarding the fact that it's specific to `alert`... I did some searching and found an article, which stated that Firefox 3 halted execution of the JavaScript thread when `alert` was called, but FF3 used an "event loop" when other synchronous operations (like `XMLHttpRequest`) ran (meaning that other timers were not blocked). It *could* be possible that FF4 is doing for `alert` what FF3 did for `XMLHttpRequest`, by using an event loop. Source for FF3 info: http://coderrr.wordpress.com/2009/06/22/firefox-3-internals-blocking-alerts-and-xmlhttprequests/ – DavidJCobb May 21 '11 at 22:47
  • 1
    @DavidJCobb Wow. Nice find. I didn't not expect FF to do that at all (it seems like a silly implementation flaw ... err ... detail), but I agree that it's like the same scenario. Consider posting an answer. –  May 22 '11 at 07:03

2 Answers2

1

I'd say the only reason you are seeing your "expected" behavior is because you are introducing a block with your while loop before the browser's timer has had a chance to fire your callback. In your doLater you have instructed the JavaScript engine to execute the callback function as soon as possible. However, you then immediately introduce an instruction that will tie up most JavaScript engines so that the callback has to wait. So FireFox 4's JavaScript engine must be a bit quicker in this instance than the others.

James Sumners
  • 14,485
  • 10
  • 59
  • 77
  • I do not agree with this. If it is correct then this implies that Javascript *asynchronous events can **preempt** other Javascript code* which goes against an event-based dispatch model. In addition, a timeout of 500ms (which is a darn long time to a computer) will still exhibit the "unexpected" behavior. –  May 21 '11 at 21:12
  • I still don't agree with this answer, but pointing out the timing led me to replace `alert` and find a Heisenburg with the test case. So a +1 for that, thanks :-) I have updated my question with additional details. –  May 21 '11 at 21:28
  • At least it helped. I'm still not sure the execution order would be guaranteed to be the order you expect here. – James Sumners May 22 '11 at 01:32
1

Your script works in my Firefox 3.6.17.

I did some searching... It would seem that Firefox 3 actually halted the JavaScript thread(s) when processing an alert. However, other synchronous operations (like XMLHttpRequest) instead used something called an "event loop", which apparently doesn't stop other timers from executing.

My guess is that Firefox 4 is now doing for alert what Firefox 3 did for XMLHttpRequest; it's using an event loop, and because of this, timers run "behind" alerts. This would seem to explain why it works for me (in FF3) but not for you (in FF4).

Source for the FF3 information.

DavidJCobb
  • 1,081
  • 7
  • 9
  • Pardon for making you wait for-ever ;-) While this source isn't the *exact* case, it is related -- an unexpected event loop is being stubbed into a "synchronous" context. I still believe it to be a "bug" but it is what it is. –  Oct 03 '11 at 17:08