AngularJS在路由更改时中止所有待处理的$ http请求

Miq*_*Ali 52 javascript angularjs

请先查看代码

app.js

var app = angular.module('Nimbus', ['ngRoute']);
Run Code Online (Sandbox Code Playgroud)

route.js

app.config(function($routeProvider) {
    $routeProvider
    .when('/login', {
        controller: 'LoginController',
        templateUrl: 'templates/pages/login.html',
        title: 'Login'
    })
    .when('/home', {
        controller: 'HomeController',
        templateUrl: 'templates/pages/home.html',
        title: 'Dashboard'
    })
    .when('/stats', {
        controller: 'StatsController',
        templateUrl: 'templates/pages/stats.html',
        title: 'Stats'
    })
}).run( function($q, $rootScope, $location, $route, Auth) {
    $rootScope.$on( "$routeChangeStart", function(event, next, current) {
        console.log("Started");


        /* this line not working */
        var canceler = $q.defer();
        canceler.resolve();

    });

    $rootScope.$on("$routeChangeSuccess", function(currentRoute, previousRoute){
        $rootScope.title = ($route.current.title) ? $route.current.title : 'Welcome';
    });
 })
Run Code Online (Sandbox Code Playgroud)

家庭controller.js

app.controller('HomeController',
    function HomeController($scope, API) {
        API.all(function(response){
            console.log(response);
        })
    }
)
Run Code Online (Sandbox Code Playgroud)

统计-controller.js

app.controller('StatsController',
    function StatsController($scope, API) {
        API.all(function(response){
            console.log(response);
        })
    }
)
Run Code Online (Sandbox Code Playgroud)

api.js

app.factory('API', ['$q','$http', function($q, $http) {    
    return {
        all: function(callback) {
            var canceler = $q.defer();
            var apiurl = 'some_url'
            $http.get(apiurl,{timeout: canceler.promise}).success(callback);
        }
    }
}]);
Run Code Online (Sandbox Code Playgroud)

当我从家搬到stats时,再次API将发送http请求,我有很多这样的http调用,我只粘贴了几行代码.

我需要的是我需要在routechangestart或success上取消所有挂起的http请求

或者其他任何实现方式?

iva*_*rni 55

我为此编写了一些概念性代码.可能需要调整以满足您的需求.有一个pendingRequests服务,它有一个用于添加,获取和取消请求的API,一个httpService包装$http并确保跟踪所有请求的服务.

通过利用$http配置对象(docs),我们可以获得取消待处理请求的方法.

我已经做了一个plnkr,但你需要快速的手指才能看到请求被取消,因为我发现的测试站点通常在半秒内响应,但你会在devtools网络选项卡中看到请求被取消.在您的情况下,您显然会触发cancelAll()来自相应事件的调用$routeProvider.

控制器就在那里展示这个概念.

DEMO

angular.module('app', [])
// This service keeps track of pending requests
.service('pendingRequests', function() {
  var pending = [];
  this.get = function() {
    return pending;
  };
  this.add = function(request) {
    pending.push(request);
  };
  this.remove = function(request) {
    pending = _.filter(pending, function(p) {
      return p.url !== request;
    });
  };
  this.cancelAll = function() {
    angular.forEach(pending, function(p) {
      p.canceller.resolve();
    });
    pending.length = 0;
  };
})
// This service wraps $http to make sure pending requests are tracked 
.service('httpService', ['$http', '$q', 'pendingRequests', function($http, $q, pendingRequests) {
  this.get = function(url) {
    var canceller = $q.defer();
    pendingRequests.add({
      url: url,
      canceller: canceller
    });
    //Request gets cancelled if the timeout-promise is resolved
    var requestPromise = $http.get(url, { timeout: canceller.promise });
    //Once a request has failed or succeeded, remove it from the pending list
    requestPromise.finally(function() {
      pendingRequests.remove(url);
    });
    return requestPromise;
  }
}])
// The controller just helps generate requests and keep a visual track of pending ones
.controller('AppCtrl', ['$scope', 'httpService', 'pendingRequests', function($scope, httpService, pendingRequests) {
  $scope.requests = [];
  $scope.$watch(function() {
    return pendingRequests.get();
  }, function(pending) {
    $scope.requests = pending;
  })

  var counter = 1;
  $scope.addRequests = function() {
    for (var i = 0, l = 9; i < l; i++) {
      httpService.get('https://public.opencpu.org/ocpu/library/?foo=' + counter++);  
    }
  };
  $scope.cancelAll = function() {
    pendingRequests.cancelAll();
  }
}]);
Run Code Online (Sandbox Code Playgroud)


Fra*_*jak 17

你可以$http.pendingRequests用来做那件事.

首先,当您提出请求时,请执行以下操作:

var cancel = $q.defer();
var request = {
    method: method,
    url: requestUrl,
    data: data,
    timeout: cancel.promise, // cancel promise, standard thing in $http request
    cancel: cancel // this is where we do our magic
};

$http(request).then(.....);
Run Code Online (Sandbox Code Playgroud)

现在,我们取消所有待处理的请求 $routeChangeStart

$rootScope.$on('$routeChangeStart', function (event, next, current) {

    $http.pendingRequests.forEach(function(request) {
        if (request.cancel) {
            request.cancel.resolve();
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

这样,您也可以通过在请求中不提供"取消"字段来"保护"某个请求被取消.

  • 好的,我还没有完全了解底层实现的工作方式。添加+1即可获得最小的工作解决方案。 (2认同)

roo*_*tar 9

我认为这是中止请求的最佳解决方案.它正在使用拦截器和$ routeChangeSuccess事件. http://blog.xebia.com/cancelling-http-requests-for-fun-and-profit/