Reputation: 28654
Imagine I have such setup. Imagine I have some map on my page and next to it there is a dialog where there is a toggle button.
Imagine when user clicks the toggle button a different request (depending on toggle state) is sent to server (which returns different type of map data depending on the request). If toggle is clicked once it receives say data about restaurants, next time it is clicked it receives data about hospitals and so on.
Also imagine when user drags a map, a refresh signal is sent to server, which sends same type of data but with updated information. For example, if user drags map when hospitals are shown on the map, again hospitals are received but with updated location.
Problem
Imagine two situations:
Assume user quickly clicks the toggle several times - then following thing will happen. First, request is sent to receive the restaurant data. But restaurant data has not arrived yet - and now before the restaurant data is received, the next toggle click happens, and request is sent to get hospital data (normally this second click on the toggle would delete restaurant data but since it is not on the map yet, it can't). So in the end we will end up with both restaurant and hospital data on the map which is what we don't want.
Imagine user clicks toggle and request is sent to receive restaurant data. But before restaurant data is received imagine user drags map (which causes refresh). What happens now due to drag is that since currently there is hospital data on the map, due to refresh, request to get updated hospital data will be sent. In the end we will again end up with hospital and restaurant data on the map.
I hope you can see the pattern of the kind of problems I am encountering here. What is the best practice to deal with such situations?
Upvotes: 2
Views: 155
Reputation: 8207
What you're describing is a simple case of race conditions.
There is no general solution for this kind of problem, it needs to be handled case-by-case. But in most cases, you probably want to display the results of the latest action user has done. If you don't have another way of knowing which request is which, you can attach some sort of identifier to the request, for example a GUID, and only display the data when the corresponding request is done.
Sometimes, the solution can be simply to disable all actions which could cause a race condition for the duration of the request, but this can deteriorate the user experience. Take for example Google Docs online editor, imagine that the whole editor would get disabled every time the auto-save function is triggered. In cases like this, it would be beneficial to store every update and compose the state from these actions. One of JavaScript that does state management like this is Redux. If you want to store data like this, you could use a database, such as EventStore.
Upvotes: 1
Reputation: 15913
I have solutions in my mind. One has the impact on User Experience and UI, the other one involves sending the last request. I will explain how:
1. Disabling the map and the button until the request is complete.
So what you can do is a loading or overlay div that stays until the request info is returned. Until this, the user is not allowed to use the map or toggle. This is UI impact but I have seen sites behaving this manner.
2. Map position. The other option is to store the map position in like local storage and match the map position again on request success. If the map is on a different position, serve a message like Search in this area etc. Google maps behave something like this manner.
3. Serve the latest ajax request and abort others:
This can be done, by pushing the requests in a queue/order and send the last one to get the response. like if you are catering it via ajax, so some code like below code, if I call getFoo
for 10 times, the last one will be fired
var ajax = null;
var getFoo = function() {
if(ajax) ajax.abort();
ajax= $.ajax({});
};
Upvotes: 3