Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

At what point in a function call is an AJAX request actually initiated by the browser?

Let's say I have a function that does a standard AJAX request:

function doXHR() {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts');
  xhr.send();
  xhr.onreadystatechange = () => {
    console.log('ready state change');
  };
}

doXHR();
console.log('done');

This code will cause the browser to start an AJAX request, but at what point in the function does the request actually start? According to this post: https://blog.raananweber.com/2015/06/17/no-there-are-no-race-conditions-in-javascript/

[Calling xhr.onreadystate() after send()] is possible, because the HTTP request is only executed after the current scope has ended its tasks. This enables the programmer to set the callbacks at any position he wishes. As JavaScript is single-threaded, the request can only be sent when this one single thread is free to run new tasks. The HTTP request is added to the list of tasks to be executed, that is managed by the engine.

But when I add a breakpoint in devtools right after the send call:

enter image description here

I do get a network request, albeit in a pending state:

enter image description here

At the breakpoint, the XHR's readystate is 1, which is XMLHttpRequest.OPENED. According to MDN's documentation, XMLHttpRequest.OPENED means that xhr.open() has been called: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState

But if I comment out xhr.send() so that only .open() is called:

enter image description here

Then I get no pending network request:

enter image description here

Thinking that perhaps I need the function scope to end in order for the request to actually be sent out, I moved the breakpoint to after the function call (and modified the code a bit to see the XHR readyState):

enter image description here

But I still get the pending network request:

enter image description here

It seems like the debugger not only freezes code execution, but also any network requests. This makes sense, as you don't want network requests to complete while you're on a breakpoint, but this also makes it impossible to tell when the network request is actually initiated.

My question is, at what point does the request actually get sent out? Does calling xhr.send() merely set up the request, but requires that the function scope end before the request is initiated? Does xhr.send() immediately initiate the request before the function scope ends? Or is there something else going on here?

like image 473
Daniel T. Avatar asked Feb 26 '17 06:02

Daniel T.


People also ask

What happens when JavaScript makes an AJAX request in a browser?

When you make an AJAX request, your browser sends an HTTP request to a given address. The server on the other end of the request responds, and returns the data to your browser. This is the same thing that happens when you navigate to a new web page.

How does an AJAX call work?

How AJAX Calls Work. AJAX uses both a browser built-in XMLHttpRequest object to get data from the web server and JavaScript and HTML DOM to display that content to the user. Despite the name “AJAX” these calls can also transport data as plain text or JSON instead of XML.

How do I know if AJAX is working?

In Laravel, we can use $request->ajax() method to check request is ajax or not.

Which AJAX method is used to send a request to a server?

By default, Ajax requests are sent using the GET HTTP method. If the POST method is required, the method can be specified by setting a value for the type option. This option affects how the contents of the data option are sent to the server.


1 Answers

send immediately initiates the request. This is at least hinted at by MDN's documentation for send.

The author of the blog you link to is correct that there are no race conditions per-se, but that does not keep you from having things happen out-of-order. An example of this would be if you load multiple <script> tags in with the async=true set on them. In this case, if one script depends on the other, you could end up in a situation where you have an unpredictable sequence of events (which is very similar to a race condition) because two asynchronous events finish at different times.

It is true that you can set onreadystatechange after calling send because even if the request request failed immediately, the event won't get dispatched until the function scope completes. The delay here is not in the dispatching of the network request, but in the dispatching of the event to say that the network request completed.

It is important to note, that networking itself is not handled in JavaScript, but rather by the browser implementation, which is native code, and could be multi-threaded (although I do not know if it is). This means that the browser is perfectly capable of handling network tasks while your javascript is running.

like image 77
Mobius Avatar answered Oct 01 '22 09:10

Mobius