A common problem working with ajax is firing duplicate requests. A common solution is to first check if a request is ongoing. I solved this problem differently by memoizing the get request for the lifetime of the request.
Memoization is storing the results of a function call and returning the cached result when the same inputs occur. This is often used to optimize expensive function calls, but I see value in using it here. In the code below we use Restangular, but the concept works just as well for any promise based request library.
function memoizedService(route) {
var service = Restangular.service(route);
var hasher = JSON.stringify;
var memoizedGetList = _.memoize(service.getList, hasher);
/**
* Get list, but if there already is a request ongoing with the same
* params then return the existing request.
* @param {Object} params
* @return {promise}
*/
service.getList = function(params) {
return memoizedGetList(params).finally(function() {
delete memoized.cache[hasher(params)];
});
}
return service;
}
var questionEndpoint = Restangular.memoizedService('question');
Make sure you install underscore with a bit of
bower install underscore --save
Then, to use the feature we would do:
questionEndpoint.getList({page: 1});
If we request page 1 when there is already a request for page 1 then the second `getList` will return the same promise that the first request returned and you will only see 1 request for page 1 in the network panel. Note importantly we also remove the cached request when the request is complete. This prevents data consistency problems: a get request can return different data over time (e.g., more records), and we want to make sure the user receives the most up to date data.