0

I've been teaching myself php and xml (among other languages) and while going through the xmlhttprequest tutorial on w3schools, I noticed the open() and send() functions are located at the end of the function and not before or out of it. This is a bit puzzling because how can one get a response from the server if the request has not yet been sent? It maybe be something simple that I have missed and I apologize if that's the case but can anyone help me with my dilemma? Thanks in advance

function loadDoc() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
     document.getElementById("demo").innerHTML = this.responseText;
    }
  };
  xhttp.open("GET", "ajax_info.txt", true);
  xhttp.send();
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • Please provide an example of the code you are puzzled by in the question here on Stack Overflow. It *sounds* like you're asking about how an event handler works, but it would be nice to be sure. – Heretic Monkey Sep 18 '18 at 15:59
  • Welcome to stackoverflow. Please include code with your question... as referencing an external site (which you haven't even linked to) can change over time, making your question redundant to future readers looking for the same answer – freefaller Sep 18 '18 at 15:59
  • Welcome to Stack Overflow! Please take the [tour], have a look around, and read through the [help], in particular [*How do I ask a good question?*](/help/how-to-ask) Post code and markup and such **as text**, not as a *picture* of text. Why: http://meta.stackoverflow.com/q/285551/157247 – T.J. Crowder Sep 18 '18 at 16:05

2 Answers2

1

It probably doesn't matter on modern browsers, but fundamentally, it's so you set up the call before sending it. In particular, so that all the handlers have been attached before asking the XHR to do something. Compare:

// Example 1
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function() {
    // Got the data
});
xhr.open("GET", "http://example.com");
xhr.send();

with

// Example 2
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com");
xhr.send();
xhr.addEventListener("load", function() {
    // Got the data
});

Browsers are not single-threaded, though they run JavaScript code in a single main thread (plus any web workers you create). So it's possible (though extraordinarily unlikely) that with Example 2, if the resource is in the browser's cache, a separate thread handling network calls could trigger the load event between the send and addEventListener calls on the JavaScript thread, see that there were no handlers registered, and not queue a task for the event loop to call the handler. Whereas with Example 1, if it triggers the load event immediately upon send, it sees an attached handler and queues a task to call it (which runs later, when the event loop comes around to processing that task).

Here's an example of that hypothetical scenario, showing the thread interaction:

Example 1 - Highly Theoretical Scenario

JavaScript Thread                          Network Thread
-----------------------------------------  --------------
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", function() {
    // Got the data
});
xhr.open("GET", "http://example.com");
xhr.send();
    (Within send: Start the send, handing
    off to the network thread)
                                           1. Start a GET on `xhr`
                                           2. It's in cache, are there any load
                                              handlers registered on `xhr`?
                                           3. Yes, queue a task to call the handler
(Done with current task)
(Pick up next task)
Call the handler

vs

Example 2 - Highly Theoretical Scenario

JavaScript Thread                          Network Thread
-----------------------------------------  --------------
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://example.com");
xhr.send();
    (Within send: Start the send, handing
    off to the network thread)
                                           1. Start a GET on `xhr`
                                           2. It's in cache, are there any load
                                              handlers registered on `xhr`?
                                           3. No, don't queue a task to call 
                                              the handler
xhr.addEventListener("load", function() {
    // Got the data
});
(Done with current task)
(Pick up next task)
(No task, do nothing)

I very much doubt any current browser would actually do that (Example 2), and I'm not aware of XHR having had a problem like this in the past. But it's theoretically possible, and there was a very similar problem, circa 2008, with setting src on an img element before hooking the load event for it. However, browsers fixed that problem, and I'd be surprised to find they were open to the Example 2 scenario above now, either, even if they or may not have been at some point in the past.

In practice, I doubt it matters. But I'd still use Example 1 if I used XMLHttpRequest (I don't, I use fetch).

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • It isn't possible. The function that calls `send` and `addEventListener` would block the event loop. Any load event that arrived between `send()` and `addEventListener()` being called would be queued until the function had finished (and `addEventListener()` *had* been called). – Quentin Sep 18 '18 at 16:05
  • @Quentin - I think you missed some detail in my final paragraph. Imagine a browser that has a thread for JavaScript, and a thread for network operations. The `send` call triggers the network operation, which (again) is on a separate thread from the JavaScript code. That thread happens to get scheduled over the JavaScript thread, determines the resource is already available, and looks for event handlers. It doesn't see any, so it doesn't queue the call. (This isn't entirely theoretical, it used to actually happen with `img`, `onload`, and `src`, back in the day.) – T.J. Crowder Sep 18 '18 at 16:07
  • While the *call* wouldn't happen until the JavaScript event loop got around to it, looking at the list of event handlers and *queuing* the calls for them (or not, if there aren't any) doesn't (necessarily) happen on the JavaScript thread. – T.J. Crowder Sep 18 '18 at 16:08
  • I agree with Quentin.@T.J.Crowder your answer is incorrect. Reordering the sequence of operations does not matter. In fact, part of the beauty of JavaScript is that you are guaranteed that the thread execution (within the sequence of instructions) will not be paused and resumed before completion – Zo72 Sep 18 '18 at 16:14
  • @Zo72 - I'm afraid you're mistaken, and this was a real issue (with `img`, not XHR) back a decade or so. Please read through the answer *in detail*. – T.J. Crowder Sep 18 '18 at 16:16
  • @T.J.Crowder I read it again. In your opinion, in the "unlikely example" the send-operation does not queue the task (because the item is cached) and the handler is called straight-away. If you were right then it's a bad implementation of the XMLHttpRequest and if you know that this was the case in 2008 then be it. – Zo72 Sep 19 '18 at 08:40
  • @Zo72 - *"...and the handler is called straight-away..."* No, I don't say that above. (That would violate JavaScript's run-to-completion semantics.) I say that the *check* for whether there are handlers is done straight-away, and then either tasks to call them are queued or not depending on whether handlers were registered. It's all hopefully academic now of course, because hopefully no browser actually does this, having learnt the lesson from `img` `load`. :-) – T.J. Crowder Sep 19 '18 at 08:44
  • 1
    @T.J.Crowder "the check for whether there are handlers is done straight-away," Okay, point taken. You are correct. so the order of those statements, at least in theory, would matter. Well done – Zo72 Sep 19 '18 at 09:03
0

The code to read the data will be in a separate function that is assigned as an event handler.

That function won't run until the response is received.

Related: How do I return the response from an asynchronous call?

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • The function won't run until the response is received either way, so... (But there **is** a reason for setting things up the way the OP mentions, with `send` being last.) – T.J. Crowder Sep 18 '18 at 16:04