AngularJS abortar todas as requisições $ http pendentes na mudança de rota

Por favor, passe pelo código primeiro

app.js

var app = angular.module('Nimbus', ['ngRoute']); 

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'; }); }) 

home-controller.js

 app.controller('HomeController', function HomeController($scope, API) { API.all(function(response){ console.log(response); }) } ) 

stats-controller.js

 app.controller('StatsController', function StatsController($scope, API) { API.all(function(response){ console.log(response); }) } ) 

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); } } }]); 

Quando eu mudo de casa para statistics, novamente a API enviará uma requisição http, eu tenho muitas chamadas http como essa, colei apenas algumas linhas de código.

O que eu preciso é que eu preciso cancelar o cancelamento de todos os pedidos HTTP pendentes em routechangestart ou sucesso

Ou alguma outra maneira de implementar o mesmo?

Eu coloquei um código conceitual para isso. Pode precisar de ajustes para atender às suas necessidades. Há um serviço pendingRequests que tem uma API para adicionar, receber e cancelar solicitações, um httpService que envolve $http e garante que todas as solicitações sejam rastreadas.

Aproveitando o object de configuração $http ( docs ), podemos obter uma maneira de cancelar uma solicitação pendente.

Eu fiz um plnkr, mas você vai precisar de dedos rápidos para ver os pedidos sendo cancelados, já que o site de teste que eu encontrei normalmente responde dentro de meio segundo, mas você verá na guia de rede devtools que os pedidos são cancelados. No seu caso, você obviamente acionaria a chamada cancelAll() nos events apropriados do $routeProvider .

O controlador está ali apenas para demonstrar o conceito.

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(); } }]); 

Você pode usar $http.pendingRequests para fazer isso.

Primeiro, quando você faz um pedido, faça o seguinte:

 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(.....); 

Agora, cancelamos todas as solicitações pendentes em $routeChangeStart

 $rootScope.$on('$routeChangeStart', function (event, next, current) { $http.pendingRequests.forEach(function(request) { if (request.cancel) { request.cancel.resolve(); } }); }); 

Dessa forma, você também pode ‘proteger’ certos pedidos de cancelamento, simplesmente não fornecendo o campo ‘cancelar’ na solicitação.

Acho que esta é a melhor solução para anular pedidos. Está usando um evento interceptor e $ routeChangeSuccess. http://blog.xebia.com/cancelling-http-requests-for-fun-and-profit/

Por favor note que eu sou novo com Angular, então isso pode não ser o ideal. Outra solução poderia ser: no pedido $ http adicionando o argumento “timeout”, o Docs eu fiz assim:

Em uma fábrica onde eu chamo todos os meus serviços de descanso, tenho essa lógica.

 module.factory('myactory', ['$http', '$q', function ($http, $q) { var canceler = $q.defer(); var urlBase = '/api/blabla'; var factory = {}; factory.CANCEL_REQUESTS = function () { canceler.resolve(); this.ENABLE_REQUESTS(); }; factory.ENABLE_REQUESTS = function () { canceler = $q.defer(); }; factory.myMethod = function () { return $http.get(urlBase, {timeout: canceler.promise}); }; factory.myOtherMethod= function () { return $http.post(urlBase, {a:a, b:b}, {timeout: canceler.promise}); }; return factory; }]); 

e na configuração do aplicativo angular eu tenho:

 return angular.module('app', ['ngRoute', 'ngSanitize', 'app.controllers', 'app.factories', 'app.filters', 'app.directives', 'ui.bootstrap', 'ngGeolocation', 'ui.select' ]) .run(['$location', '$rootScope', 'myFactory', function($location, $rootScope, myFactory) { $rootScope.$on('$routeChangeSuccess', function (event, current, previous) { myFactory.CANCEL_REQUESTS(); $rootScope.title = current.$$route.title; }); }]); 

Dessa forma, ele captura todas as alterações de “rota” e interrompe toda a solicitação configurada com esse “timer” para que você possa selecionar o que é crítico para você.

Espero que ajude a alguém. Saudações