How to deal with out-of-sequence Ajax requests? - ajax

What is the best way deal with out-of-sequence Ajax requests (preferably using a jQuery)?
For example, an Ajax request is sent from the user's browser anytime a field changes. A user may change dog_name to "Fluffy", but a moment later, she changes it to "Spot". The first request is delayed for whatever reason, so it arrives at the server after the second, and her dog ends up being called "Fluffy" instead of "Spot".
I could pass along a client-side timestamp along with each request, and have the server track it as part of each Dog record and disregard earlier requests to change the same field (but only if there is a difference of less than 5 minutes, in case the user changes the time on her machine).
Is this approach sufficiently robust, or is there a better, more standardized approach?
EDIT:
Matt made a great point in his comment. It's much better to serialize requests to change the same field, so is there a standard way of implementing Ajax request queues?
EDIT #2
In response to #cherouvim's comment, I don't think I'd have to lock the form. The field changes to reflect the user's change, a change request is placed into the queue. If a request to change the same field is waiting in the queue, delete that old request. 2 things I still would have to address:
Placing a request into the queue is an asynchronous task. I could have the callback handler from the previous Ajax request send the next request in the queue. Javascript code isn't multi-threaded (or... is it?)
If a request fails, I would need the user interface to reflect the state of the last successful request. So, if the user changes the dog's name to "Spot" and the Ajax request fails, the field would have to be set back to "Fluffy" (the last value successfully committed).
What issues am I missing?

First of all you need to serialize server side processing for each client. If you are programming in Java then synchronizing execution on the http session object is sufficient. Serializing will help in case the second update comes while the first is being processed.
A second enhancement you can implement in your entity updating is http://en.wikipedia.org/wiki/Optimistic_concurrency_control. You add a version property (and column) for your entity. Each time an update happens this is incremented once. In fact the update statement looks like:
update ... set version=6 ... where id=? and version=5;
If affected rows from above pseudoquery query are 0 then someone else has managed to update the entity first. What you do then is up to you. Note that you need to be rendering the version on the html update form of the entity as a hidden parameter and sending it back to the server each time you update. On return you have to write back the updated version.
Generally the first enhancement would be enough. The second one will improve the system in case many people are editing the same entities at the same time. It solves the "lost update" problem.

I would implement a queue on the client side with chaining of successful requests or rollbacks on unsuccessful requests.
You need to define "unsuccessful", be it a timeout or a returned value.

Related

How to distinguish two responses that have the same status code but different response body?

I have an application where users can take part of puzzle solving events. I have an API endpoint /events/{id} that is used to get data associated to a certain event.
Based on whether the event has ended, the response will differ:
If the event has ended, the endpoint will return event name, participants, scores etc. with status code 200
If the event has not ended, the endpoint will return event name, start time, end time, puzzles etc. with status code 200.
On the client-side, what is the best way to distinguish these two responses from each other to decide which page to display, results page or event page? Is this a good way to accomplish my goal?
Some might answer that I should already know on the client-side whether the event has ended and then query for data accordingly. But what if user uses the address bar to navigate to an event? Then I will have no data to know, whether it truly has ended. I wouldn't like to first make an API call to know that it has (not) ended and then make another one for results/puzzles.
pass a boolean isFinished and return it inside of response object. If your response object is already defined, create a wrapper that has the previous response dto and a boolean flag.
Also we did use a solution like this in one of our projects at work for a big company so I would say it is somewhat industry accepted way of doing it.

Tracking ajax request status in a Flux application

We're refactoring a large Backbone application to use Flux to help solve some tight coupling and event / data flow issues. However, we haven't yet figured out how to handle cases where we need to know the status of a specific ajax request
When a controller component requests some data from a flux store, and that data has not yet been loaded, we trigger an ajax request to fetch the data. We dispatch one action when the request is initiated, and another on success or failure.
This is sufficient to load the correct data, and update the stores once the data has been loaded. But, we have some cases where we need to know whether a certain ajax request is pending or completed - sometimes just to display a spinner in one or more views, or sometimes to block other actions until the data is loaded.
Are there any patterns that people are using for this sort of behavior in flux/react apps? here are a few approaches I've considered:
Have a 'request status' store that knows whether there is a pending, completed, or failed request of any type. This works well for simple cases like 'is there a pending request for workout data', but becomes complicated if we want to get more granular 'is there a pending request for workout id 123'
Have all of the stores track whether the relevant data requests are pending or not, and return that status data as part of the store api - i.e. WorkoutStore.getWorkout would return something like { status: 'pending', data: {} }. The problem with this approach is that it seems like this sort of state shouldn't be mixed in with the domain data as it's really a separate concern. Also, now every consumer of the workout store api needs to handle this 'response with status' instead of just the relevant domain data
Ignore request status - either the data is there and the controller/view act on it, or the data isn't there and the controller/view don't act on it. Simpler, but probably not sufficient for our purposes
The solutions to this problem vary quite a bit based on the needs of the application, and I can't say that I know of a one-size-fits-all solution.
Often, #3 is fine, and your React components simply decide whether to show a spinner based on whether a prop is null.
When you need better tracking of requests, you may need this tracking at the level of the request itself, or you might instead need this at the level of the data that is being updated. These are two different needs that require similar, but slightly different approaches. Both solutions use a client-side id to track the request, like you have described in #1.
If the component that calls the action creator needs to know the state of the request, you create a requestID and hang on to that in this.state. Later, the component will examine a collection of requests passed down through props to see if the requestID is present as a key. If so, it can read the request status there, and clear the state. A RequestStore sounds like a fine place to store and manage that state.
However, if you need to know the status of the request at the level of a particular record, one way to manage this is to have your records in the store hold on to both a clientID and a more canonical (server-side) id. This way you can create the clientID as part of an optimistic update, and when the response comes back from the server, you can clear the clientID.
Another solution that we've been using on a few projects at Facebook is to create an action queue as an adjunct to the store. The action queue is a second storage area. All of your getters draw from both the store itself and the data in the action queue. So your optimistic updates don't actually update the store until the response comes back from the server.

ExtJS 4 - How to check if all current ajax requests are completed and then perform an action?

I have a page which fires Ajax requests for validations at server side. I need to perform an action when all the ajax requests have finished loading or are completed.
For this, I am using Ext.Ajax.isLoading() in a recursive function in following way:
function chechValid(){
if(Ext.Ajax.isLoading()){
checkValid();
}else{
//Code for Action 1
}
}//EOF
checkValid();
//Code for Action 2
The problem is that when I do this, browsers give the following errors:
Mozill FF - too much recursions
IE - Stack overflow at line:18134
If this recursion is a heavy thing for the browsers, then how to perform a task when all the Ajax requests have finished loading?
Using delay is not what I want as, if delay is used then browser begins executing the other code (like 'Code for Action 2' as shared above) which is not what is expected.
The main aim is that the browser shouldn't execute anything unless all the Ajax requests are complete and once completed then it should perform a particular action.
Any suggestions/help on this one?
Thanks in Advance.
PS: Using ExtJs 4.0.7
(Updated)More Detail about the actual situation:-
Here is brief description of the situtaion being faced - There is a form, in which I need to perform server side validations on various fields. I am doing so by firing an ajax request on blur event. Depending upon the server response of validation Ajax fired on blur, fields are marked invalid and form submission is not allowed. (Avoiding 'change' event as that causes alot of overhead on server due to high number of Ajas requests and also leads to fluctuating effects on a field when response from various such Ajax requests are received).
Things are working fine except in one case - when user modifies the value of a field and instead of 'tab'bing out from the field she directly clicks at the save button. In such a case, though, the blur event gets fired but the processing of 'Save' doesn't wait for Ajax Validation response and submits the form. Thus, I somehow need to check if Ajax requests have finihed loading and the process the saving of form. requestComplete would unfortunately not serve the purpose here. And if try using the recursion, then of course, the browser is hung due to high usage of resources. Same case occurs if I try using a pause script work around ( as shared here - Javascript Sleep).
Any possible workaround for this one?
TIA
Your method will lead to infinite recursion.
A better way is to register a callback function in Ext.Ajax.requestcomplete, something like this (not tested):
Ext.Ajax.on('requestcomplete', function(conn, response, options) {
if (!Ext.Ajax.isLoading()) {
//your action...
}
}
};
Unless I am misunderstanding the issue couldn't you create a couple of globals. I know globals are bad, but in this case it will save you quite a bit of headache. One global would be "formReady" and initially set it to false, the other would be "ajaxActive" and set to false. You would also add an onSubmit method that would validate that "formReady" was true and if not alert the user that validation was occurring (or you could set a timeout for form submission again and have a second validation that checks to see if "ajaxActive" is true). When the AJAX call is made it would set the variable "ajaxActive" to true and once complete would set formReady to true. You could also potentially resubmit the form automatically if the response from the AJAX was that the form was good.
Ext.Ajax.request() returns a transaction object when you call it, which is unique and allows you to recognise and abort specific Ajax requests.
By just calling Ext.Ajax.isLoading() without a specified transaction object, it defaults to the last request, which is why you have to call it recursively at the moment.
If it were me, I'd create an array of these transaction objects as you fire them off, and pass each of those in as optional parameters to the Ext.Ajax.isLoading() function to check if a particular request has finished. If it has, you can remove that transaction object from the array, and only progress with the save when your array is empty.
This would get round your recursion problem, since you've always got a finite number of requests that you're waiting on.
if (Object.keys(Ext.Ajax.requests).length === 0) console.log("No active requests");

Best practice for combining requests with possible different return types

Background
I'm working on a web application utilizing AJAX to fetch content/data and what have you - nothing out of the ordinary.
On the server-side certain events can happen that the client-side JavaScript framework needs to be notified about and vice versa. These events are not always related to the users immediate actions. It is not an option to wait for the next page refresh to include them in the document or to stick them in some hidden fields because the user might never submit a form.
Right now it is design in such a way that events to and from the server are riding a long with the users requests. For instance if the user clicks a 'view details' link this would fire a request to the server to fetch some HTML or JSON with details about the clicked item. Along with this request or rather the response, a server-side (invoked) event will return with the content.
Question/issue 1:
I'm unsure how to control the queue of events going to the server. They can ride along with user invoked events, but what if these does not occur, the events will get lost. I imagine having a timer setup up to send these events to the server in the case the user does not perform some action. What do you think?
Question/issue 2:
With regards to the responds, some being requested as HTML some as JSON it is a bit tricky as I would have to somehow wrap al this data for allow for both formalized (and unrelated) events and perhaps HTML content, depending on the request, to return to the client. Any suggestions? anything I should be away about, for instance returning HTML content wrapped in a JSON bundle?
Update:
Do you know of any framework that uses an approach like this, that I can look at for inspiration (that is a framework that wraps events/requests in a package along with data)?
I am tackling a similar problem to yours at the moment. On your first question, I was thinking of implementing some sort of timer on the client side that makes an asycnhronous call for the content on expiry.
On your second question, I normaly just return JSON representing the data I need, and then present it by manipulating the Document model. I prefer to keep things consistent.
As for best practices, I cant say for sure that what I am doing is or complies to any best practice, but it works for our present requirement.
You might want to also consider the performance impact of having multiple clients making asynchrounous calls to your web server at regular intervals.

how to clear the cache data when using ajax?

I am using Ajax to retrieve the data from server as below based on some ID to perform auto suggest function. however when i submit the form and update the database, the auto suggest field suppose should not contain anything for this ID anymore, but it will still retrieve data from its cache. do anyone know how to clear the cache and make the Ajax sending request to get the latest data from server every time i press the button? Pls help i really stuck on this whole weeks and couldnt find the solution.
For example: when ID field is 00001, auto suggest field will be 1,2,3. After i submit the form and update the database, when i search for 00001 again, it should not contain anything but it does, it still cache the data as 1,2,3 in suggest field...
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
var data=xmlhttp.responseText;
alert(data);
}
}
xmlhttp.open("GET","gethint.php?q="+str,true);
xmlhttp.send();
I had this problem once before. This is probably something you can fix in your server settings. What the server does is get a server request, build the answer, and when the same request is done again it sends the same response it built before.
To easily avoid this problem, I added an extra request parameter (a UID).
so:
xmlhttp.open("GET","gethint.php?q="+str+**"?something"=RANDOMGUID**,true);
this way you always ha a unique request.
Works with IE8
xmlHttp.open("GET", URL, true);
xmlHttp.setRequestHeader("Cache-Control", "no-cache");
xmlHttp.setRequestHeader("Pragma", "no-cache");
xmlHttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
you could use http headers to prevent the response from being cached:
Cache-Control: no-cache
Expires: Mon, 24 Oct 2005 16:13:22 GMT
Another option is to add another parameter to the url that varies everytime (for example the current time in millis), that way for the browser you ask another url and the cache won't be used.
Easiest thing to do is use jQuery#ajax and disable caching.
jQuery will suffix a parameter ?somenumber to your ajax call which just is sufficient to persuade the browser it cannot use cached data.
I came across this once. Here's the answer I got: Why does jQuery.ajax() add a parameter to the url? .
You could do the same thing manually too, but you would have to check if the addition of the parameter is all there is to it.
No code provided but some guidance that can help you manage account state consistently across many potential tabs, history, devices, etc:
First, the more condensed version in one long paragraph:
If you want a consistent view for an account, regardless of history back/forward buttons, extra tabs or extra windows (even with different IPs/devices), you can use an increment counter and a heartbeat (heartbeat can be implemented as an XMLHttpRequest send() during a setInterval call configured to say 2 seconds). The increment is managed at the server. The client provides the counter value on each call to server. On each request, the server checks the counter value provided by the client with its own saved value. The server produces the next counter value, persists it, and returns that counter value in the reply so client can use it on its next call. If the client provided the expected counter value, it was a "good" request. If the value provided was different than what the server had stored, the client's call was a "bad" request. Honor good requests. Server may only partly honor bad requests. The client's "next" call could be the next heartbeat or any other request on that account. Multiple client views into that account can overlap but essentially one client only would get the next good call. All other clients would get bad next calls because their counter values will no longer match what the server has stored. If you use one account view, every call to server should be a good call once the session is initiated. [A session can last when browser javascript maintains the counter value, but unless you use cookies or the like, you cannot extend a session if the page is refreshed since javascript would be reinitialized. This means every first call to page would be a "bad" call.] If you use history back, some other tab, or some other device, you should be able to use it, but you will get a bad call at a minimum whenever you switch from one to the other. To limit these bad call cases, turn off heartbeat when that browser view is inactive. Note, don't even implement a heartbeat if you don't mind showing the user a possibly stale page for a prolonged time or if the particular page is unlikely to be stale (but this question assumes you can get stale data on user's browser view).
Let's add more detail:
Every request to a server from an existing opened browser page provides the counter value. This can be, for example, during a form submit or during javascript XMLHttpRequest object .send().
Requests typed from url bar by the user may not have a counter value sent. This and logon can just be treated as having an incorrect count value. These would be examples of "bad" calls, and should be handled as gracefully as possible but should generally not be allowed to update the account if you want a consistent view.
Every request seeking to modify the account (a "writer") must have provided the anticipated counter value (which can be updated at the server other than as +1 if you have more elaborate needs but must be anticipated/unique for a next request). At the server end, if the counter value is the expected one, then process the request variables normally and allow write access. Then include in the reply to client the next legit value the server will expect for that variable (eg, cnt++) and persist that value on the server end (eg, update counter value in database or in some other server file) so that the server will know the next legit counter value to expect whenever the next request comes in for that account.
A request that is a simple "read" is processed the same way as a write request except that if it is a bad request (if the counter doesn't match), a read is more likely to be able to be safely processed.
All requests that provide a different counter value than expected ("bad" requests) still result in the updating of the counter at the server and still result in the client's reply getting the good next expected counter value; however, those bad requests should be ignored to the extent they ask to update the account. Bad requests could even result in more drastic action (such as logging user out).
Client javascript will update the value of counter upon every server reply to what the server returns so that this updated counter value is sent back on any next call (eg, on heartbeat or any talk to server). Every client request will always get a legit next value sent back but only the client that uses that first will be treated as ok by server.
The other clients (ie, any client request that doesn't provide the expected counter value) will instead be given a safe state, eg, the current state as per the database while ignoring any write/update requests. The server can treat the "bad" client calls in other more drastic ways, eg, by logging the user out or whatever, but primarily just make sure to honor at most the bad client's safe read requests, not updating the account in any way.
The heartbeat is necessary only if you want a clean view in short order. To make it light on server, you can have the heartbeat be a simple ping (sending the counter value along). If acknowledged as the good client, you can be done for that heartbeat. If you were a bad client however, then server can return say good fresh info which can be used by javascript in heartbeat code to update the GUI. The heartbeat can be to a different php server page or main one but if different make sure that page gets consistent view of server saved counter variable (eg, use a database).
Another feature you may want to implement for an account is "active/inactive status. The client would be inactive if the mouse position has not changed for a number of seconds or minutes (and no keys typed or other user input during that time). The heartbeat can deactivate itself (clearInterval) when client is inactive. On every user input check if heartbeat is stopped and if so restart it. Heartbeat restart also means user is changing from inactive to active. Stopping the heartbeat would conserve client/server resources when user is browsing on other tab or afk. When becoming active again, you can do things like log out user if they were inactive for a long time, etc... or just do nothing new except restart heartbeat. [Remember, the reply to a heartbeat could indicate the heartbeat request was "bad".. which might possibly be a "drastic" reason to log user out as mentioned above.]
I know that an answer has been accepted, but it didn't worked in my case. I already had no-cache header added. In my case this was the solution that really worked, because if you add a code after the request, it might not get executed in time for the second piece of code to run successfully:
x = new XMLHttpRequest();
x.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//execute the other code or function only when the page is really loaded!
}
};
x.open("GET", "add your url here", true);
x.send();

Resources