Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: cancel an $http request using timeout property

I have seen lots and lots of posts on this topic, and lots of web articles, but I remain stumped with my problem. I found this post very useful but my timeoutRequest() function is never being called.

I am using a promise with the timeout property of $http but the underlying HTTP request is not being cancelled. I think the promise itself is being resolved but the request is not cancelled.

My controller behaviours looks like this:

$scope.enquiriesSelected = function() {
    $scope.cancelHttpRequests();
    $location.path("/enquiries");
};

$scope.cancelHttpRequests = function () {
    console.log(canceller.promise.$$state);
    canceller.resolve("User cancelled");
    console.log(canceller.promise.$$state);
};

My HTTP request promise looks like this:

var canceller = $q.defer();

$scope.searchResultsPromise = $http({
        url: "/api/customers/customersearch",
        method: "POST",
        data: criteria,
        timeout: canceller.promise 
    })
    .success(function(data) {
        $scope.customerSearchResults = data;
    });

I have tried various methods to get this to work, including putting the canceller in the $scope.

I have been looking through the AngularJS source code and I find these lines:

if (timeout > 0) {
    var timeoutId = $browserDefer(timeoutRequest, timeout);
} else if (isPromiseLike(timeout)) {
    timeout.then(timeoutRequest);
}

function timeoutRequest() {
    jsonpDone && jsonpDone();
    xhr && xhr.abort();
}

However the execution path does not reach these lines when my promise is resolved. The xhr.abort() is never called and this is the only place in the AngularJS source code that aborts an HTTP request.

Inspecting with the console in F12 (Chrome) when trying to cancel the request reveals that the $$state of the promise changes from 0 to 1 so I'm reasonably sure that the promise is resolving. However in network traffic the HTTP request is not being cancelled. I cannot navigate to another page until the HTTP request is completed.

Can anyone help?

M

like image 236
serlingpa Avatar asked Jun 02 '15 08:06

serlingpa


1 Answers

What you are describing is actually the correct way of cancelling an $http request using the timeout property. I have created this Plunkr which showcases this behaviour being as close as possible to the code you have provided. You can see that when the "Submit request with timeout" button is clicked a request is submitted and the timeout promise is resolved after 100 msec (since the request returns so fast that you don't really have time to click something to cancel it):

$scope.requestWithTimeout = function() {
  $timeout(function(){canceller.resolve("User cancelled");}, 100);
  $scope.submitRequest();
}

The $http request error callback checks the status of the response and displays an appropriate error message, in which you can see that the request was actually cancelled after 100msec. You can also verify this by observing the request in the network tab of your browser's developer tools.

$scope.submitRequest = function() {
    // Reset the canceler promise
    canceller = $q.defer();
    $scope.status = 'Request submitted';
    var startTime = (new Date()).getTime();
    $http({ 
      url: 'style.css',
      method: 'GET',
      timeout: canceller.promise 
    })
    .success(function(data) {
      var endTime = (new Date()).getTime();
      $scope.status = 'Request response returned after ' + (endTime - startTime) + ' msec.';
    })
    .error(function(data, status) {
      var endTime = (new Date()).getTime();
      if(status === 0) {
        $scope.status = 'Request timed out after ' + (endTime - startTime) + ' msec.';
      } else {
        $scope.status = 'Request returned with error after ' + (endTime - startTime) + ' msec.';
      }
    });
  }

Hopefully you can use this as an example to find what is wrong with your code and correct it. Otherwise please create a Plunkr (or something similar) with the code that is not working so that I can help you further.

like image 87
Christina Avatar answered Nov 04 '22 11:11

Christina