1

Here is a simple snipped to do an Ajax request

var req = new XMLHttpRequest();
req.open('GET', 'http://www.mozilla.org/', true);
req.send(null); // First - send the request
// Then bind for the "result"
req.onreadystatechange = function (e) {
    if (req.readyState == 4 && req.status == 200) {
        // ...
    }
};

What I am doing here:

  1. Sending the Ajax request.
  2. And then binding for the result callback.

If you think of this code as multithreaded - it is obvious that you can bind to onreadystatechage after the request has finished (due to scheduling) and it will never be called.

But in reactor-based code, this will work as expected all times since the reactor will not run until after all my code has finished running for that iteration.

Which is the case in browsers? Has this been documented somewhere?

Ignore that fact that an Ajax request is a slow thing and this might never happen in practice. I'm just giving it as an async example (think websocket if ajax is too slow for you).

Emil Ivanov
  • 37,300
  • 12
  • 75
  • 90
  • If you do Ajax, you are STRONGLY encouraged to adopt a JavaScript library or toolkit. Different browsers have different quirks for Ajax and you can't know them all. – Stephen Chung Aug 08 '11 at 02:05

4 Answers4

2

In theory no, firing of event handlers are supposed to happen on the event queue so would have to happen in a time slice after the current time slice completes, which would mean that the req.onreadystatechange = ... happens before any events are handled. See javascript - event driven and concurrency issues? to understand JavaScript's concurrency model (at least in the browser).

In practice, Firefox used to have (may still have) a bug where the onreadystatechange event in particular was fired concurrently with the event queue of the frame whose XMLHttpRequest object was used to send the request. I got into the habit of having my onreadystatechange handlers do a setTimeout(0, ...) to make sure I didn't get nasty interleavings on Firefox.

It's also possible if you use an XMLHttpRequest object cross-frame as in new otherWindow.XMLHttpRequest(...) because then the response could be handled on the other frame's event queue before the current time-slice (in this frame's event queue) finishes.

Community
  • 1
  • 1
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
2

JavaScript is not multithreaded in that sense. After you have said.send(null), you will finish executing your current block of code, which includes that onreadystatechange, and only then will events be fired. Your code will not be interrupted between those two sentences for an event firing - the event will be added to an event queue (buffered, if you will), and when there is time, the event will fire, calling all the handlers associated to it. It should call handlers that have been added between the creation of the XMLHttpRequest object and the firing of the event.

At least, this is my interpretation of the issue. For more information, visit Timing and synchronization in Javascript, at dev.opera.

Federico Lebrón
  • 1,772
  • 1
  • 11
  • 10
1

Is it possible to “miss” an async event in JS if you subscribe for it after you've asked for its triggering?

No, this is not possible - if you bind the handler before the event occurs.

The event occurs anyway. When it does, all handlers that are registered at this point in time will be called.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
1

Theoretically it is possible.

To avoid it put req.onreadystatechange = ... before req.send(null);.

nobody
  • 10,599
  • 4
  • 26
  • 43