How to destroy unresolved promise
Asked Answered
V

3

13

Have a look into the code snippet

$scope.getSongs = function(keyword){
     songServices.getSongList(keyword).then(
         function(resp){
             $scope.songList = resp.data.songList;
         }
     );
}

Here getSongList simply returns list of songs from server by an HTTP request.

And in my HTML:

<input auto-focus type="text" placeholder="Enter song ID/Keyword" ng-model="keyword" ng-change="getSongs()">

The problem here is with behaviour of promises, sometimes if some promise takes more time(even in ms.) to get resolved then it shows false data. when you search for 'AKON' lets say promise with first strike 'A' returns last then it refreshes the scope with false data, Is there any way to stop or discard promise which have not been resolved before sending another promise to server, or how can I handle such kind of scenario.

Thanks in advance.

Venter answered 12/6, 2015 at 14:6 Comment(1)
without going into enough detail for an answer, you can chain a promise as an intermediary that can be used to reject outdated promises.Splashdown
L
10

$http calls can be cancelled, by passing a promise in the 'timeout' config option, and resolving that promise.

From the documentation:

timeout – {number|Promise} – timeout in milliseconds, or promise that should abort the request when resolved.

Example:

var canceler = $q.defer();
$http.get(someUrl, { timeout: canceler.promise });

// later: cancel the http request

canceler.resolve();
Leprous answered 12/6, 2015 at 14:9 Comment(0)
L
6

Rather than destroy the promise it might be better not to make a call until the user has stopped typing. you can use the ng-options directive to set a debounce timer. That way the action will only get executed once the user has stopped typing.

<input auto-focus type="text" placeholder="Enter song ID/Keyword" ng-model="keyword" ng-change="getSongs" ng-model-options="{ debounce: 500}">

Lewendal answered 12/6, 2015 at 14:14 Comment(2)
Instead of "rather", I'd say "In addition to". Even if the second request is sent 500ms. after a first one, its response might come earlier.Leprous
The problem is we don't know how abstracted the $http service is based on the code example provided. On top of that the angular team decided not to implement an actual cancel api on $q promises. The easiest thing for him to do would be to return the keyword value that was searched for by his service and check it against the current keyword value on the $scope and if they don't match then don't update the list.Lewendal
O
2

You could create a destroyable promise from an ordinary promise easily enough:

var destroyablePromise = function(p) {
  var r = $q.defer();

  p.then(function(a) { if (p) { r.resolve(a); }}, 
         function(a) { if (p) { r.reject(a); }},
         function(a) { if (p) { r.notify(a); }});

  r.promise.destroy = function() {
    p = null;
  };
  return r.promise;
}

Et voilà!

Obligation answered 12/6, 2015 at 15:36 Comment(2)
I like this solution, initially I thought I would need to reject the promise to cancel it, but this is event better, nothing will ever happen! Is there a risk of memory leaks with this?Gastrectomy
There isn't a risk of a new memory leak. Obviously, if you leak r, you leak p too.Obligation

© 2022 - 2024 — McMap. All rights reserved.