[英]AngularJS abort all pending $http requests on route change
Please go through the code first请先通过代码
app.js应用程序.js
var app = angular.module('Nimbus', ['ngRoute']);
route.js路由.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家庭控制器.js
app.controller('HomeController',
function HomeController($scope, API) {
API.all(function(response){
console.log(response);
})
}
)
stats-controller.js stats-controller.js
app.controller('StatsController',
function StatsController($scope, API) {
API.all(function(response){
console.log(response);
})
}
)
api.js 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);
}
}
}]);
When I move from home to stats , again API will send http request, I have many http calls like this, I pasted only few lines of code.当我从家搬到 stats 时,API 将再次发送 http 请求,我有很多这样的 http 调用,我只粘贴了几行代码。
What I need is I need to
cancel
abort all pending http requests on routechangestart or success我需要的是我需要在 routechangestart 或成功时
取消
中止所有挂起的 http 请求
Or any other way to implement the same ?或任何其他方式来实现相同的?
I put together some conceptual code for this.我为此整理了一些概念性代码。 It might need tweaking to fit your needs.
它可能需要调整以满足您的需求。 There's a
pendingRequests
service that has an API for adding, getting and cancelling requests, a httpService
that wraps $http
and makes sure all requests are tracked.有一个
pendingRequests
服务,它有一个用于添加、获取和取消请求的 API,一个包装$http
并确保跟踪所有请求的httpService
。
By leveraging the $http
config object ( docs ) we can get a way to cancel a pending request.通过利用
$http
配置对象 ( docs ),我们可以获得一种取消待处理请求的方法。
I've made a plnkr, but you're going to need quick fingers to see requests getting cancelled since the test-site I found typically responds within half a second, but you will see in the devtools network tab that requests do get cancelled.我已经制作了一个 plnkr,但是您需要快速查看请求被取消,因为我发现的测试站点通常会在半秒内响应,但是您会在 devtools 网络选项卡中看到请求确实被取消了。 In your case, you would obviously trigger the
cancelAll()
call on the appropriate events from $routeProvider
.在您的情况下,您显然会在
$routeProvider
的适当事件上触发cancelAll()
调用。
The controller is just there to demonstrate the concept.控制器只是为了演示这个概念。
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();
}
}]);
You can use $http.pendingRequests
to do that.您可以使用
$http.pendingRequests
来做到这一点。
First, when you make request, do this:首先,当您提出请求时,请执行以下操作:
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(.....);
Now, we cancel all our pending requests in $routeChangeStart
现在,我们取消所有在
$routeChangeStart
待处理请求
$rootScope.$on('$routeChangeStart', function (event, next, current) {
$http.pendingRequests.forEach(function(request) {
if (request.cancel) {
request.cancel.resolve();
}
});
});
This way you can also 'protect' certain request from being cancelled by simply not providing 'cancel' field in request.通过这种方式,您还可以通过在请求中不提供“取消”字段来“保护”某些请求不被取消。
I think this is the best solution to abort requests.我认为这是中止请求的最佳解决方案。 It's using an interceptor and $routeChangeSuccess event.
它使用拦截器和 $routeChangeSuccess 事件。 http://blog.xebia.com/cancelling-http-requests-for-fun-and-profit/
http://blog.xebia.com/cancelling-http-requests-for-fun-and-profit/
Please notice that im new with Angular so this may not be optimal.请注意,我是 Angular 的新手,所以这可能不是最佳选择。 Another solution could be: on the $http request adding the "timeout" argument, Docs I did it this way:
另一个解决方案可能是:在 $http 请求中添加“超时”参数,文档我是这样做的:
In a factory where I call all my Rest services, have this logic.在我调用所有 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;
}]);
and on the angular app configuration I have:在角度应用程序配置上,我有:
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;
});
}]);
This way it catches all the "route" changes and stops all the request configured with that "timer" so you can select what is critical for you.通过这种方式,它会捕获所有“路由”更改并停止使用该“计时器”配置的所有请求,以便您可以选择对您来说至关重要的内容。
I hope it helps to someone.我希望它对某人有所帮助。 Regards
问候
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.