coderrr

June 22, 2009

Firefox 3 internals, blocking alerts and XMLHttpRequests

Filed under: firefox, javascript, Uncategorized — Tags: , — coderrr @ 7:25 pm

In my quest to find something which acts similar to an alert() box in Firefox 3 (for anti-anti-frame-busting), but without the annoying user-experience, I discovered a few things that I thought I should share. Note this is all FF3 specific.

Why do alert() and other javascript dialogs block javascript execution and in particular javascript timers?
It actually turns out that they do this implicitly, as a side effect of being modal dialogs. Modal dialogs halt the execution of the thread they have been created from until the user closes the dialog. Since all the javascript from a single page is run in a single thread the dialog effectively stops all of it.

embedding/components/windowwatcher/src/nsWindowWatcher.cpp:949

// alert() eventually calls this function
nsWindowWatcher::OpenWindowJSInternal(...)
/* ... */
    printf("About to show the dialog...\n");
    newChrome->ShowAsModal();
    printf("You won't see this until the user closes the dialog\n");

Why don’t synchronous XMLHttpRequests block javascript timers?
Synchronous XHRs do block the execution of the javascript they were called from but not the execution of other javascript timers. That’s a little unexpected given the nature of other synchronous things like the above modal dialog. You would expect some code which blocks your javascript function to be blocking the actual thread its executing on. But Firefox does something interesting while making the requesting.

content/base/src/nsXMLHTTPRequest.cpp:1986

 // If we're synchronous, spin an event loop here and wait
  if (!(mState & XML_HTTP_REQUEST_ASYNC)) {
    nsIThread *thread = NS_GetCurrentThread();
    while (mState & XML_HTTP_REQUEST_SYNCLOOPING) {
      if (!NS_ProcessNextEvent(thread)) {
        rv = NS_ERROR_UNEXPECTED;
        break;
      }
    }
  }

Internally Firefox processes the synchronous request asynchronously, in an event loop. And one of the things that this event loop does is schedule timers for execution.

Even though this event loop is asynchronously processing the XHR request. It is still synchronous in the sense that it will block normal execution of the thread until it returns. This can produce some interesting effects. Take this example which performs two overlapping synchronous XHRs:

setInterval('document.body.innerHTML += "."', 1000)

xhr = new XMLHttpRequest()
xhr.open("GET", "http://request-which-takes-1-second.com/", false)

setTimeout(function() {
  xhr2 = new XMLHttpRequest()
  xhr2.open("GET", "http://request-which-takes-10-seconds.com/", false)

  document.body.innerHTML += 'start2'
  xhr2.send(null)
  document.body.innerHTML += 'done2'
},500)

document.body.innerHTML += 'start1'
xhr.send(null)
document.body.innerHTML += 'done1'

In this example we queue the 2nd XHR to start about half a second after the first one starts. Since the first one only takes a second we might expect to see the text done1 before we see done2. But since it was the event loop of the first XHR which actually initiated the 2nd XHR, the first XHR won’t return until the function which initiated the 2nd XHR returns. We end up getting output like this:

start1start2...............done2done1

1 Comment »

  1. I am not seeing what you describe in Firefox 3.6.16. Instead I am seeing what I would expect:
    start1done1start2done2…….

    If I change the first interval to 50ms, I see this (also what I would expect):
    start1done1…..start2done2…….

    The code at nsXMLHTTPRequest.cpp:1986 is still the same though, maybe something else has changed?

    Comment by David Rees — May 24, 2011 @ 3:47 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Silver is the New Black Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 27 other followers

%d bloggers like this: