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();
Related
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.
Here is my sample code. (The reason I need to send synchronous requests is that actually I need to send several requests and each requests depends on the previous request's response. And the reason I need to set callbacks is that I want to show some spinner, so users knows the status of the script.)
var xmlhttp =new XMLHttpRequest();
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==2) {
document.getElementById("p2").style.color = "blue"; //statment 1
}
if (xmlhttp.readyState==4) {
document.getElementById("p2").style.color = "red"; //statment 2
}
}
xmlhttp.open("GET","ajax_info.txt",false);
xmlhttp.send();
balblabla(); // a time-cost function
Then I have 2 questions.
First, when will statement 1 and statement 2 actually get executed?
Is it guaranteed to get executed before balblabla()?
Second, Even if statement 1 and statement 2 get executed, seems browser won't actually change the displayed color until blablabla() is finished.
Is there a way to make color change got displayed before blablabla() finished? (assuming blablabla() takes a long time)
Thanks!
If the XHR is synchronous then the callbacks are executed before .send() returns. In other words before blablabla().
Browser DOM updates are asynchronous. Or rather, the redraws are asynchronous (DOM update/reflow can at times be synchronous but it won't draw to screen, just update data structures).
So, even if you insist on not learning how to write asynchronous programs by using synchronous XMLHttpRequest you can't draw anything synchronously. You'd be better off writing everything asynchronous.
note: To be clear, redraw only happens when the javascript interpreter have nothing else to run. In other words, the browser window will only be updated after blablabla() completes running.
If blablabla() takes a long time to execute, you can break up the loop using setTimeout() to make it asynchronous. Alternatively you can try using webworkers.
I'm using below for AJAX
var myRequest=new XMLHttpRequest();
myRequest.open("POST", "abc.php", false);
So when it's false & i do database connection in PHP (abc.php file) & run query it gives result number of rows 1 on desktop. But not on iPad.
When i changed it to
myRequest.open("POST", "abc.php", true);
In iPad as well on desktop it will give number of rows as 1. By making it false why mysql query not give result in AJAX file on iPad?
The third parameter on the open() method of the XML HTTP request defines of the XML HTTP request should be async or not. An asynchronous call doesn't wait for other calls (synchronous) to invoke.
The third parameter specifies whether the request made is asynchronous or a synchronous request..To be specific about syncronous and asynchronous request
Synchronous -- The script execution gets stopped and will only proceed when you get back a reply from the server
Asynchronous--Here the script will the processed and will not wait for a reply..When there is a reply your page will be updated with a specific result.
In most caes recommend to use aynchronous calls,because even it the server side call returns any error the whole web page do not break.
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.
I use a XMLHttpRequest on a signup form to see if the username they entered has been taken already. The script runs fine, but I notice that there's some time delay when making the request - the webpage is frozen for a second, after sending the request.
Is there a way to have the request "in the background" and not cause any lag on the front end? I like Twitter's implementation: it shows an spinning hourglass icon while it's searching the database. How do I get something similar?
You want to use asynchronous XHR -- currently you're performing a synchronous request, so the page has to freeze until the load has complete. Asynchronous XHR calls a callbck function you provide with the load status updates.
If memory serves you just need to do
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) loadFinished();
}
xhr.open(requestType, url, true);
Where true makes the request asynchronous.
You need to specify that XMLHttpRequest operate asynchronously--in the background. Then you can provide a callback function so users can continue browsing until the operation is complete.
Many sites simply show an animated GIF while waiting for the operation to return, which probably gives the user the impression that you're looking for since it looks like something is happening. You can design and download one of those AJAX-spinning indicators easily at http://www.ajaxload.info/.