AngularJS在路由改变时中止所有挂起的$ http请求
请先通过代码
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'; }); })
家庭controller.js
app.controller('HomeController', function HomeController($scope, API) { API.all(function(response){ console.log(response); }) } )
统计-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); } } }]);
当我从家到统计,再次API将发送http请求,我有很多这样的http调用,我只粘贴了几行代码。
我需要的是我需要取消在routechangestart或成功中止所有挂起的http请求
还是用其他方法来实现呢?
我为此编写了一些概念性代码。 它可能需要调整,以适应您的需求。 有一个pendingRequests
服务,它有一个用于添加,获取和取消请求的API,一个包装$http
的httpService
,并确保所有请求都被跟踪。
通过利用$http
configuration对象( docs ),我们可以获得取消挂起的请求的方法。
我已经做了一个plnkr,但你需要快速的手指看到请求被取消,因为我发现的testing网站通常在半秒内响应,但是你会在devtoolsnetworking标签中看到请求被取消。 在你的情况下,你显然会从$routeProvider
的相应事件触发cancelAll()
调用。
控制器就在这里来展示这个概念。
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(); } }]);
你可以使用$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(.....);
现在,我们取消$routeChangeStart
所有未决请求
$rootScope.$on('$routeChangeStart', function (event, next, current) { $http.pendingRequests.forEach(function(request) { if (request.cancel) { request.cancel.resolve(); } }); });
这样,您也可以通过简单地在请求中不提供“取消”字段来“保护”某些请求被取消。
我认为这是中止请求的最佳解决scheme。 它使用拦截器和$ routeChangeSuccess事件。 http://blog.xebia.com/cancelling-http-requests-for-fun-and-profit/
请注意,即时通讯与Angular新,所以这可能不是最佳的。 另一个解决scheme可能是:在$ http请求中添加“超时”参数, Docs我这样做:
在我打电话给我所有rest服务的工厂,有这个逻辑。
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; }]);
并在angular度应用程序configuration我有:
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; }); }]);
通过这种方式,它可以捕获所有的“路由”更改,并停止使用该“定时器”configuration的所有请求,以便select对您来说至关重要的内容。
我希望对某人有帮助 问候