Mootools XHR request: synchronous and/or chained? - javascript

I have a couple of XHR requests, which are handled by the Mootools Request class. This class offers some options to time the requests appropriately. What I'm doing:
XHR: Post form data
XHR: Refresh main pane
XHR: Refresh subpane
Of course, requests 2 & 3 must wait before 1 is finished. So these are triggered within the onComplete event handler. However, the Request class offers options for handling multiple XHR requests. My question is about these two:
The option link can be set to chain, in order to 'chain' them, or, as the Moo docs state:
Any calls made to start while the request is running will be chained up, and will take place as soon as the current request has finished, one after another.
The option async can be set to false, to prevent later requests from executing. According to the Moo docs:
If set to false, the requests will be synchronous and freeze the browser during request.
Apart from the browser freezing part, what is exactly the difference? Which one should I use for request no. 1? Is it better to do it synchronously, so I'm sure nothing else executes in the meantime? And how about using both, does that make any sense?

well. the difference between link: chain and async: false is simple.
first axiom - you are reusing your request instance and not making a new one. even if you are not, it can work with async. eg, if you have async: false, then this code:
new Request({async:false}).send();
// this one below will not run until the UI thread has finished
new Request({async:false}).send();
// nor will this
somefunc();
if you go with chain:
var req = new Request({link: "chain"});
req.send();
// this won't run until the previous request has completed:
req.send();
// this will run independently of the above and may finish first as
// they are not synchronous and this is a brand new instance.
new Request().send();

The chained requests are asynchronous, when one ends it triggers the second one and so on, so you can have several requests without jamming the browser with all the requests at the same time.
The chained requests do not freeze your browser.

Related

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:
I do get a network request, albeit in a pending state:
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:
Then I get no pending network request:
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):
But I still get the pending network request:
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?
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.

Is it possible to cancel asynchronous call independently of its current state?

When I type text into my textfield widget I send request with every character typed into it to get matching data from the server.
When I type really fast I swarm server with the requests and this causes to freeze my control, I managed to create throttling mechanism where I set how many ms client should wait before sending request. This requires to set arbitrary constant ms to wait. The better solution would be to just cancel sending previous request when the next key button is pressed.
Is it possible to cancel AJAX request independently of its current state? If yes, how to achieve this?
Call XMLHttpRequest.abort()
See: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/abort
You'll have to track your requests somehow, perhaps in an array.
requests = [];
xhr = new XMLHttpRequest(),
method = "GET",
url = "https://developer.mozilla.org/";
requests.push(xhr);
MDN says :
The XMLHttpRequest.abort() method aborts the request if it has already
been sent. When a request is aborted, its readyState is set to 0
(UNSENT), but the readystatechange event is not fired.
What's important to note here is that while you will be able to .abort() requests on the client side (and thus not have to worry about the server's response), you are still swarming your server because all those requests are still being sent.
My opinion is that you had it right the first time, by implementing a mechanism that limits the frequency of AJAX requests. You mentioned that you had a problem with this freezing your control (I assume you mean that the browser is either taking longer to respond to user actions, or stops responding completely), and this could be a sign that there is a problem with the way your application handles asynchronous code.
Make sure you are using async APIs like Promise correctly, avoid loops that do heavy processing or just wait around in client code, and make your event processing (i.e your AJAX callback) simple and fast to reduce the impact on the user.

Is it possible to abort a synchronous XmlHttpRequest?

I have written a JavaScript function that asynchronously calls a web service using XmlHttpRequest. I have been asked to make this function finish its work before the page is rendered.
I thought I could make the AJAX request synchronous but I don't want this to make the page hang too long - I'd like to abort the request after, say, 1 second if a response isn't received.
Is it possible to abort a synchronous XmlHttpRequest?
You can't:
http://www.hunlock.com/blogs/Snippets:_Synchronous_AJAX sais:
"Synchronous AJAX (Really SJAX -- Synchronous Javascript and XML) is modal which means that javascript will stop processing your program until a result has been obtained from the server. While the request is processing, the browser is effectively frozen. The browser treats the call like an alert box or a prompt box only it doesn't wait for input from the user, but on input by the remote server"
Once the browser runs the sync request, it will wait until it will get a response.
First of all, synchronous AJAX calls are evil because they are blocking the whole JavaScript browser engine (which you are aware of).
Is simply doing the call asynchronously and discarding the result if it arrives later than after a second is not enough? If you really want to wait for the result you can still use setTimeout() (jQuery for convenience, not required):
var result;
var xhr = $.ajax('/url', function(response) {
result = response;
});
setTimeout(function() {
if(result) {
//AJAX call done within a second, proceed with rendering
} else {
//One second passed, no result yet, discard it and move on
xhr.abort();
}
}, 1000);
With this approach you are not blocking the browser while still you don't have to wait for the AJAX call.
XMLHttpRequest support abort method, you can get more details about it here: http://www.w3.org/TR/XMLHttpRequest/#the-abort-method
But you need to check how many browserы support it. For example, abort was introduced in Windows Internet Explorer 7 and above.
Before or after calling send() method of XMLHttpRequest object you can setup a timer for n-seconds delay which will interrupt an asynchronous operation which is in progress.
It is possible in IE.Use the timeout property.
the code below worked for me
xmlhttp.open("method","url",false);
xmlhttp.timeout="time in ms";
xmlhttp.ontimeout=function(){};
xmlhttp.send();

JavaScript: How long the browser can expect to perform JS before opening a new page?

Page has several links.
I need to track click on the links the user.
That is, when user click's on a link sent to Ajax request to my server, my server processes the request and returns some data. Further, these data are processed on the client side as needed and sent to the server statistics.
All of these requests and data processing require a certain time.
My question is practical: how long the browser can expect to perform all these actions? there is a limit in time?
Just now I have the following options:
When you click the link, using js return false. Perform all necessary functions, and only then, to execute the opening of the new window.
Thus I avoid problems with the expectation of the browser.
If you want to ensure that the link is not followed until your AJAX request has completed, you should do a synchronous request. For instance:
link.onclick = function () {
var xhr = new XMLHTTPRequest(); // and the cross-browser equivalents
xhr.open('GET', 'yourscript.cgi?data1=foo&data2=bar', false);
// false means do the request synchronously
xhr.send(); // won't return till the request is complete
// you can access the data as xhr.responseText or xhr.responseXML
};
This is a much more reliable (and probably faster) way of doing the necessary notifications than waiting a certain period of time.

Any issue with setTimeout calling itself?

I have read a handful of setTimeout questions and none appear to relate to the question I have in mind. I know I could use setInterval() but it is not my prefered option.
I have a web app that could in theory be running a day or more without a page refresh and more than one check a minute. Am I likely to get tripped up if my function calls itself several hundred (or more) times using setInterval? Will I reach "stack overflow" for example?
If I use setInterval there is a remote possibility of two requests being run at the same time especially on slow connections (where a second one is raised before the first is finished). I know I could create flags to test if a request is already active, but I'm afraid of false positives.
My solution is to have a function call my jquery ajax code, do its thing, and then as part of ajaxComplete, it does a setInterval to call itself again in X seconds. This method also allows me to alter the duration between calls, so if my server is busy(slow), one reply can set a flag to increase the time between ajax calls.
Sample code of my idea...
function ServiceOrderSync()
{
// 1. Sync stage changes from client with the server
// 2. Sync new orders from server to this client
$.ajax( { "data": dataurl,
"success": function(data)
{ // process my data },
"complete": function(data)
{
// Queue the next sync
setTimeout( ServiceOrderSync, 15000 );
});
}
You won't get a stack overflow, since the call isn't truly recursive (I call it "pseudo-recursive")
JavaScript is an event driven language, and when you call setTimeout it just queues an event in the list of pending events, and code execution then just continues from where you are and the call stack gets completely unwound before the next event is pulled from that list.
p.s. I'd strongly recommend using Promises if you're using jQuery to handle async code.

Categories

Resources