1

Here is the situation: You have a user who spams input on your AngularJS app, and this of course is creating all kinds of async data calls on the backend. The problem is, as each of these data fetchs come back, the user will see the data change multiple times on the screen and hopefully the data the user finally rested on is the one that comes in last so that's what they see.

But we can't count on that because async means that order isn't guaranteed. There is very much a possibility that the data for Page C arrives before the data for Page B that the user skipped over without waiting for display. Now, the user sees the data for Page B because that returned last but they think they are seeing Page C. How do we protect against this?

2 Answers 2

1

$http accepts a canceller parameter, which is a promise that can be used to cancel a previous request. You will want to cancel the request when you're about to make a new request. Here is a rudimentary example. Note that best practices do not suggest using $http from within your controller.

var canceller = $q.defer();
 
$http.get("/api/movies/slow/2", { timeout: canceller.promise })
     .then(function(response){
        $scope.movie = response.data;
    });
 
$scope.cancel = function(){
    canceller.resolve("user cancelled");  
};

Read more here: http://odetocode.com/blogs/scott/archive/2014/04/24/canceling-http-requests-in-angularjs.aspx

Sign up to request clarification or add additional context in comments.

2 Comments

In my experience, this still caused flapping because even a cancelled lookup might have progressed beyond the point where it could be cancelled. That's why I went with the token solution.
This especially becomes the case when you have multiple promises chained together.
0

The solution to this is pretty simple: use a token! Each promise will carry a local copy of the token when it was created and will check the master token to make sure it is still relevant:

var self = this;

// our token generator
self.generateToken = function() { 
    return return Math.floor(100000000 + Math.random() * 900000000);
}

// our latest token
self.getData = function() {
    self.asyncToken = self.createToken();
    var myToken = self.asyncToken;

    var request = $http({url: "http://google.com"});
    var promise = request.then(function(response) {
        if (myToken !== self.asyncToken) {
            console.log("Got data for expired request.  Ignoring.");
            return;
        }
        // this is data we wanted, so we continue
        self.doStuff(response.data);
    });

    return promise;
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.