I am not really sure it is possible in JavaScript, so I thought I'd ask. :)
Say we have 100 requests to be done and want to speed things up.
What I was thinking of doing is:
Create a loop that will launch the first 5 ajax calls
Wait until they all return (success - call a function to update the dom / error) - not sure how, maybe with a global counter?
Repeat until all requests are done.
Considering browser JavaScript does not support thread, can we "exploit" the async functionality to do that?
Do you think it would work, or there are inherent problems doing that in JavaScript?
Yes, I have done something similar to this before. The basic process is:
Create a stack to store your jobs (requests, in this case).
Start out by executing 3 or 4 of the requests.
In the callback of the request, pop the next job out of the stack and execute it (giving it the same callback).
I'd say, the comment from Dancrumb is the "answer" to this question, but anyway...
Current browsers do limit HTTP requests, so you can even easily just start all 100 request immediately, and the browser will take care of sending those requests as fast as possible, but limited to a decent number of parallel requests.
So, just start them all immediately and trust on the browser.
However, this may change in the future (the number of parallel requests that a browser sends increases as end-user internet bandwidth increases and technology advances).
EDIT: you should also think and read about the meaning of "asynchronous" in a javascript context.. asynchronous here just means that you give up control about something to some other part of a system. so "sending" an async request just means, that you tell the browser to do so! you do not control the browser, you just tell it to send that request and please notify me about the outcome.
It's actually slower to break up 100 requests and batch post them 5 at a time whilst waiting for them to complete till you send the next batch. You might be better off simply sending 100 requests, remember JavaScript is single threaded so it can only resolve 1 response at a time anyways.
A better way is set up a batch request service that accepts something like:
/ajax_batch?req1=/some/request.json&req2=/other/request.json
And so on. Basically you send multiple requests in a single HTTP request. The response of such a request would look like:
[
{"reqName":"req1","data":{}},
{"reqName":"req2","data":{}}
]
Your ajax_batch service would resolve each request and send back the results in proper order. Client side, you keep track of what you sent and what you expect, so you can match up the results to the correct requests. Downside, it takes quite some coding.
The speed gain would come entirely from a massive reduction of HTTP requests.
There's a limit on how many requests you send because the url length has a limit iirc.
DWR does exactly that afaik.
Related
Official documentation at jQuery does not mention it.
Possible confusion: I know I can use ajax to gain control over timeout, but my question is different.
Scenario:
I am using post to grab data from a backend which I know will take a long (sometimes very very long) time to load.
Question:
Will my javascript request ever timeout or will it always wait until backend is loaded, even if it takes a few minutes?
Jquery uses the native XMLHttpRequest module to make requests.
The XMLHttpRequest.timeout property is an unsigned long representing the number of milliseconds a request can take before automatically being terminated. The default value is 0, which means there is no timeout.
Reading the source code of the jquery library, the ajax method does not set a timeout in and way, hence it is save to say that the request does not timeout.
But you can explicitly set a timeout in both jquery and the native module.
this does not mean that your request will not timeout, since the server usually does impose a bail timeout strategy, usually long responses timeout from the server side. you could consider chunking or streaming as a safe and convenient solution.
github jquery ajax source:
https://github.com/jquery/jquery/tree/2d4f53416e5f74fa98e0c1d66b6f3c285a12f0ce/src/ajax
The timeout of a request is, by default, controlled by the browser and the receiving server, whichever cancels the request first. I believe most browsers have a 60 second timeout by default. The server can be any arbitrary value.
Will my javascript request ever timeout or will it always wait until backend is loaded, even if it takes a few minutes?
The answer to this is therefore, yes, your request will timeout at an arbitrary point. If you want to control the amount of time you force your users to wait for a request then you can specifically set this time by using the timeout property of the $.ajax call. This overrides any timeout set in the browser or on the server.
15 seconds should be more than enough. If a request is taking longer than that I'd suggest you change the pattern you're using to generate the response.
HTTP Request timeout is a server side configuration not a client side configuration. Requests submitted via Jquery code is no different.
You might want to have a test against the return code from the last request and add exception handling to your code (like resubmit the request)
Always check the response code and a common strategy is to rety. https://www.lifewire.com/g00/troubleshooting-network-error-messages-4102727
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.
Will an aborted XMLHttpRequest still download the response from the server?
At what point in the request lifecycle does it differ from a regular request?
Do different browsers behave differently?
Is it bad practise to abort requests?
No, the download will (should) cancel (does in my browser at least)
When a request is aborted, its readyState is changed to XMLHttpRequest.UNSENT (0) and the request's status code is set to 0. -- MDN
No, at least hopefully not. They should be following the spec.
In my opinion, definitely not. It's a waste of bandwidth and other resources to have requests you no longer need running in the background. Much better to abort them.
Two recent use-cases from personal experience:
A table with various parameters for filtering. Depending on the parameters selected, the resulting request sometimes took a while to complete. If you selected a slow set of parameters A, and then a fast set of parameters B before A completed, you'd first see the results of B in the table, but then A would eventually complete and "replace" the contents of the table so you'd suddenly see A instead.
Solution: Abort the previous incomplete request before starting the next one.
SPA with pages with sometimes long running requests, for example the previously mentioned table. When navigating away to a different page, there were sometimes several requests running in the background for stuff no longer needed.
Solution: Register those requests to be aborted when the page/component was unmounted.
I'm working on a simple chat implementation in a function that has an ajax call that invokes a setTimeout to call itself on success. This runs every 30 seconds or so. This works fine, but I'd like a more immediate notification when a message has come. I'm seeing a lot of examples for long polling with jQuery code that looks something like this:
function poll()
{
$.ajax(
{
data:{"foo":"bar"},
url:"webservice.do",
success:function(msg)
{
doSomething(msg);
},
complete:poll
});
}
I understand how this works, but this will just keep repeatedly sending requests to the server immediately. Seems to me there needs to be some logic on the server that will hold off until something has changed, otherwise a response is immediately sent back, even if there is nothing new to report. Is this handled purely in javascript or am I missing something to be implemented server-side? If it is handled on the server, is pausing server execution really a good idea? In all of your experience, what is a better way of handling this? Is my setTimeout() method sufficient, maybe with just a smaller timeout?
I know about websockets, but as they are not widely supported yet, I'd like to stick to current-gen techniques.
Do no pause the sever execution... it will lead to drying out server resources if lot of people try to chat...
Use client side to manage the pause time as you did with the setTimeout but with lower delay
You missed the long part in "long polling". It is incumbent on the server to not return unless there's something interesting to say. See this article for more discussion.
You've identified the trade-off, open connections to the web server, therefore consuming http connections (i.e. the response must block server side) vs frequent 'is there anything new' requests therefore consuming bandwidth. WebSockets may be an option if your browser base can support them (most 'modern' browsers http://caniuse.com/websockets)
There is no proper way to handle this on the javascript side through traditional ajax polling as you will always have a lag at one end or the other if you are looking to throttle the amount of requests being made. Take a look at a nodeJS based solution or perhaps even look at the Ajax Push Engine www.ape-project.org which is PHP based.
I'm just wondering..is it possible to receive multiple responses from a single ajax call?
I'm thinking purely for aesthetic purposes to update the status on the client side.
I have a single ajax method that's called on form submit
$.ajax({
url: 'ajax-process.php',
data: data,
dataType: 'json',
type: 'post',
success: function (j) {
}
});
I can only get one response from the server-side. Is it possible to retrieve intermittent statuses? Such as:
Default (first): Creating account
Next: Sending email confirmation
Next: Done
Thanks for your help! :)
From a single ajax call, I don't think it is possible.
What you could do is check frequently where the process is (it's what is used for the upload bars in gmail for example). You do a first ajax request to launch the process, and then a series of ajax request to ask the server how he is doing. When the server answers "I'm done", you're good to go, and until that you can make the server respond and say the current state.
There is something called comet which you can set up to "push" requests to client, however it is probably way more than what you are wanting to invest in, time-wise.
You can open up a steady stream from the server, so that it continues to output, however I'm not sure how client-side script can handle these as individual "messages". Think about it like a server that outputs some info to the browser, does more work, outputs some more to the browser, does more work, etc. This shows up more or less in real time to the browser as printed text. It is one long response, but it is still one response. I think ajax only handles a response once it finished being sent, but maybe someone else will know more than me on the topic.
But you couldn't have the server output several individual responses without reloading itself, at least not with PHP, because once you start outputting the response, the response has begun and you can't chop that up without finishing the response, which happens when the script is done executing.
Your best bet is with the steady stream, but again, I'm not sure how ajax handles getting responses in chunks.
Quick Update
Based on the notes for this plugin:
[http://plugins.jquery.com/project/ajax-http-stream]
things don't look promising. Specifically:
Apparently the trend is to disallow access to the xmlhttprequest.responseText before the request is complete (stupid imo). Sorry there's nothing I can do to fix this
Thus, not only can you not get what you want in one request, you probably can't get it multiple requests, unless you want to break up the actual server-side process into several parts, and only have it continue to the next step when an ajax function triggers it.
Another option would be to have your script write it's status at specific points to another file on the server, call it "status.xml" or "status.txt". Have your first ajax function initialize the process, and have a second ajax function that queries this status file and outputs that to the user.
It is possible, but it has more to do with your backend script. As Anthony mentioned there is a tech called comet. Another term I've heard is called "Long polling". The idea is that you delay the time in which your php(insert language of choice) script finished processing.
In php you can do something like this:
while($response !== 'I'm done'){
sleep(1);
}else{
return $some_value;
exit();
}
This code stops your script from completely finishing. sleep(1) allows the script to stop and lets the server rest for 1 millisecond, before it loops back through. You can adjust the sleep time based on your needs. In php the amount of time the script sleeps is not counted agains your server timeout time.
You'll obviously need to make more checks for you code. You'll probably also want to allow for an abort script call. Something like sending a get request to kill the backend script. Maybe on the javascript unload event.
In the tests that I've done. I made the initial ajax call, and when the value was returned, I made another ajax call, that way your back end script wont time out.
I've only played around with this on my local server, so i'm not sure how real world this is, but it works.