如何在AngularJS中取消$ http请求?

在AngularJS中给定一个Ajax请求

$http.get("/backend/").success(callback); 

如果发起另一个请求(相同的后端,例如不同的参数),取消该请求最有效的方法是什么。

通过超时参数将此function添加到1.1.5版本中 :

 var canceler = $q.defer(); $http.get('/someUrl', {timeout: canceler.promise}).success(successCallback); // later... canceler.resolve(); // Aborts the $http request if it isn't finished. 

当前版本的AngularJS不支持取消$http发出的请求。 有一个pull请求打开来增加这个function,但是这个PR还没有被审查,所以目前还不清楚它是否会把它变成AngularJS的核心。

取消Angular $ http Ajax的超时属性在Angular 1.3.15中不起作用。 对于那些不能等待这个被修复的问题,我正在分享一个包装在Angular中的jQuery Ajax解决scheme。

解决scheme涉及两项服务:

  • HttpService(jQuery Ajax函数的封装);
  • PendingRequestsService(跟踪未决/打开的Ajax请求)

这里是PendingRequestsService服务:

  (function (angular) { 'use strict'; var app = angular.module('app'); app.service('PendingRequestsService', ["$log", function ($log) { var $this = this; var 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.xhr.abort(); p.deferred.reject(); }); pending.length = 0; }; }]);})(window.angular); 

HttpService服务:

  (function (angular) { 'use strict'; var app = angular.module('app'); app.service('HttpService', ['$http', '$q', "$log", 'PendingRequestsService', function ($http, $q, $log, pendingRequests) { this.post = function (url, params) { var deferred = $q.defer(); var xhr = $.ASI.callMethod({ url: url, data: params, error: function() { $log.log("ajax error"); } }); pendingRequests.add({ url: url, xhr: xhr, deferred: deferred }); xhr.done(function (data, textStatus, jqXhr) { deferred.resolve(data); }) .fail(function (jqXhr, textStatus, errorThrown) { deferred.reject(errorThrown); }).always(function (dataOrjqXhr, textStatus, jqXhrErrorThrown) { //Once a request has failed or succeeded, remove it from the pending list pendingRequests.remove(url); }); return deferred.promise; } }]); })(window.angular); 

在你加载数据的时候,你可以使用HttpService而不是$ http:

 (function (angular) { angular.module('app').service('dataService', ["HttpService", function (httpService) { this.getResources = function (params) { return httpService.post('/serverMethod', { param: params }); }; }]); })(window.angular); 

后来在你的代码中,你想加载数据:

 (function (angular) { var app = angular.module('app'); app.controller('YourController', ["DataService", "PendingRequestsService", function (httpService, pendingRequestsService) { dataService .getResources(params) .then(function (data) { // do stuff }); ... // later that day cancel requests pendingRequestsService.cancelAll(); }]); })(window.angular); 

出于某种原因,config.timeout不适用于我。 我使用这种方法:

 let cancelRequest = $q.defer(); let cancelPromise = cancelRequest.promise; let httpPromise = $http.get(...); $q.race({ cancelPromise, httpPromise }) .then(function (result) { ... }); 

如果你想通过ui-router取消stateChangeStart的挂起请求,你可以使用如下所示:

//在服务中

  var deferred = $q.defer(); var scope = this; $http.get(URL, {timeout : deferred.promise, cancel : deferred}).success(function(data){ //do something deferred.resolve(dataUsage); }).error(function(){ deferred.reject(); }); return deferred.promise; 

/ /在UIrouterconfiguration

 $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) { //To cancel pending request when change state angular.forEach($http.pendingRequests, function(request) { if (request.cancel && request.timeout) { request.cancel.resolve(); } }); }); 

这通过使用中止方法来装饰$ http服务来增强接受的答案,如下所示…

 'use strict'; angular.module('admin') .config(["$provide", function ($provide) { $provide.decorator('$http', ["$delegate", "$q", function ($delegate, $q) { var getFn = $delegate.get; var cancelerMap = {}; function getCancelerKey(method, url) { var formattedMethod = method.toLowerCase(); var formattedUrl = encodeURI(url).toLowerCase().split("?")[0]; return formattedMethod + "~" + formattedUrl; } $delegate.get = function () { var cancelerKey, canceler, method; var args = [].slice.call(arguments); var url = args[0]; var config = args[1] || {}; if (config.timeout == null) { method = "GET"; cancelerKey = getCancelerKey(method, url); canceler = $q.defer(); cancelerMap[cancelerKey] = canceler; config.timeout = canceler.promise; args[1] = config; } return getFn.apply(null, args); }; $delegate.abort = function (request) { console.log("aborting"); var cancelerKey, canceler; cancelerKey = getCancelerKey(request.method, request.url); canceler = cancelerMap[cancelerKey]; if (canceler != null) { console.log("aborting", cancelerKey); if (request.timeout != null && typeof request.timeout !== "number") { canceler.resolve(); delete cancelerMap[cancelerKey]; } } }; return $delegate; }]); }]); 

这个代码是做什么的?

要取消请求,必须设置“承诺”超时。 如果HTTP请求没有设置超时,那么代码会添加一个“承诺”超时。 (如果超时已经设置,则没有任何改变)。

但是,要解决承诺,我们需要处理“延期”。 因此,我们使用地图,以便稍后可以检索“延迟”。 当我们调用abort方法时,从地图中检索“deferred”,然后调用resolve方法取消http请求。

希望这有助于某人。

限制

目前这只适用于$ http.get,但您可以添加$ http.post的代码等等

如何使用 …

然后,您可以使用它,例如,状态更改,如下所示…

 rootScope.$on('$stateChangeStart', function (event, toState, toParams) { angular.forEach($http.pendingRequests, function (request) { $http.abort(request); }); });