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/.
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.
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.
I want to show a loading message while sending http request and hide loading on request complete, and i want to use this for all the http request. Is there any global function in angular to do this..
A JavaScript HTTP request will not block and you will provide a callback which is called when the request is complete. This means that you could do this (pseudocode, since you didn't provide example code):
function callback(httpResponse) {
hideLoadingMessage();
dostuffWithResponse(httpResponse);
}
// callback is callled when HTTP request is complete
doHttpRequest(params, callback);
// the code after continues to execute despite the HTTP request not being ready
showLoadingMessage();
So the code execution continues after the HTTP request is sent. The callback will be called when the HTTP request is complete. In practice you need to also handle errors.
Quick Google search returned a fair amount of results for Angular:
Loading spinner you can implement onClick.
http://ngmodules.org/modules/angular-loading-spinner
Previously asked question with similar circumstances:
Showing Spinner GIF during $http request in angular
And finally, codepen.io examples (might be broken now though)
http://codetunnel.io/how-to-do-loading-spinners-the-angular-way/
I would highly recommend trying before asking in future. We need code examples of what you've tried or where you are at right now. This isn't a simple piece of code unless you're using a plugin (which you could have found yourself).
I'd recommend in future, try providing some context and examples.
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 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();