Search code examples
javascriptangularjspromiserestangular

Angular, restangular - abort search call if more current one comes in


I have to pull some data from a service using a restangular call. The server has recently gotten slow - so I was looking for a way to possibly abort the call (or maybe just the promise) if a newer call comes in and tell my service to use the most recent call. Here is the service call -

  MySearchService.prototype.search = function(query) {

           return $q(function(resolve, reject) {
               var url = '/services/search';
               Restangular.oneUrl(url, url)
                    .customPOST(query)
                    .then(resolve)
                    .catch(reject);
           });
  };

I was thinking something like

.withHttpConfig({hasNewSearch: abort.promise}) <<not sure you can put custom key in here
abort.resolve();

But I don't think that's how you hook onto it. I am looking for a way to cancel the call if there is a newer call, perhaps this is entirely with the promise, and not really restangular at all? Would appreciate any advice. Thank you!


Solution

  • This is actually a cool problem, typically called last or flatMapLatest.

    // we want something that takes a function and only cares about the last result
    function last(fn){ // fn returns a promise
      var lastValue = null; // the last promise to check against
      return function(){ 
        // call the function, and mark it as the last call
        lastValue = fn.apply(this, arguments); 
        var p = lastValue;
        return p.then(function validateLast(v){ // call the function, when it resolves
            if(p === lastValue){ // if we're still the "last call" when we resolved
                return v; // we're done, successful call
            } else {
                // a newer one came, resolve with it and verify no one came since
                return lastValue.then(validateLast);
            }
        });
    }
    

    This would let you do something like

    MySearchService.prototype.search = last(function(query) {
               // removed antipattern
               return Restangular.oneUrl('/services/search', '/services/search')
                                 .customPOST(query);
    });