with - ¿Cómo cancelar una solicitud de $ http en AngularJS?
http get angularjs example (7)
Aquí hay una versión que maneja múltiples solicitudes, también comprueba el estado cancelado en la devolución de llamada para suprimir los errores en el bloque de errores. (en Mecanografiado)
nivel de controlador:
requests = new Map<string, ng.IDeferred<{}>>();
en mi http obtener:
getSomething(): void {
let url = ''/api/someaction'';
this.cancel(url); // cancel if this url is in progress
var req = this.$q.defer();
this.requests.set(url, req);
let config: ng.IRequestShortcutConfig = {
params: { id: someId}
, timeout: req.promise // <--- promise to trigger cancellation
};
this.$http.post(url, this.getPayload(), config).then(
promiseValue => this.updateEditor(promiseValue.data as IEditor),
reason => {
// if legitimate exception, show error in UI
if (!this.isCancelled(req)) {
this.showError(url, reason)
}
},
).finally(() => { });
}
métodos de ayuda
cancel(url: string) {
this.requests.forEach((req,key) => {
if (key == url)
req.resolve(''cancelled'');
});
this.requests.delete(url);
}
isCancelled(req: ng.IDeferred<{}>) {
var p = req.promise as any; // as any because typings are missing $$state
return p.$$state && p.$$state.value == ''cancelled'';
}
ahora mirando la pestaña de la red, veo que funciona maravillosamente. Llamé al método 4 veces y solo el último pasó.
Dada una solicitud de Ajax en AngularJS
$http.get("/backend/").success(callback);
¿Cuál es la forma más efectiva de cancelar esa solicitud si se lanza otra solicitud (el mismo back-end, diferentes parámetros, por ejemplo).
Esta característica se agregó a la versión 1.1.5 a través de un parámetro de tiempo de espera:
var canceler = $q.defer();
$http.get(''/someUrl'', {timeout: canceler.promise}).success(successCallback);
// later...
canceler.resolve(); // Aborts the $http request if it isn''t finished.
Esto mejora la respuesta aceptada al decorar el servicio $ http con un método de cancelación de la siguiente manera ...
''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;
}]);
}]);
¿QUÉ ESTÁ HACIENDO ESTE CÓDIGO?
Para cancelar una solicitud, se debe establecer un tiempo de espera de "promesa". Si no se establece el tiempo de espera en la solicitud HTTP, el código agrega un tiempo de espera de "promesa". (Si se establece un tiempo de espera ya no se cambia nada).
Sin embargo, para resolver la promesa, necesitamos un control sobre el "diferido". Por lo tanto, usamos un mapa para que podamos recuperar el "diferido" más tarde. Cuando llamamos al método abort, el "diferido" se recupera del mapa y luego llamamos al método resolve para cancelar la solicitud http.
Espero que esto ayude a alguien.
LIMITACIONES
Actualmente, esto solo funciona para $ http.get pero puede agregar código para $ http.post y así sucesivamente
CÓMO UTILIZAR ...
Puede usarlo, por ejemplo, en el cambio de estado, de la siguiente manera ...
rootScope.$on(''$stateChangeStart'', function (event, toState, toParams) {
angular.forEach($http.pendingRequests, function (request) {
$http.abort(request);
});
});
La cancelación de Angular $ http Ajax con la propiedad de tiempo de espera no funciona en Angular 1.3.15. Para aquellos que no pueden esperar a que esto se solucione, estoy compartiendo una solución jQuery Ajax envuelta en Angular.
La solución involucra dos servicios:
- HttpService (un envoltorio alrededor de la función jQuery Ajax);
- PendingRequestsService (rastrea las solicitudes pendientes / abiertas de Ajax)
Aquí va el servicio 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);
El servicio 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);
Más adelante en su servicio cuando esté cargando datos, usaría HttpService en lugar de $ http:
(function (angular) {
angular.module(''app'').service(''dataService'', ["HttpService", function (httpService) {
this.getResources = function (params) {
return httpService.post(''/serverMethod'', { param: params });
};
}]);
})(window.angular);
Más tarde en su código, desea cargar los datos:
(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);
La cancelación de solicitudes emitidas con $http
no es compatible con la versión actual de AngularJS. Se ha abierto una solicitud de extracción para agregar esta capacidad, pero este PR todavía no se ha revisado, por lo que no está claro si se convertirá en el núcleo de AngularJS.
Por alguna razón, config.timeout no funciona para mí. Usé este enfoque:
let cancelRequest = $q.defer();
let cancelPromise = cancelRequest.promise;
let httpPromise = $http.get(...);
$q.race({ cancelPromise, httpPromise })
.then(function (result) {
...
});
Y cancelRequest.resolve () para cancelar. En realidad, no cancela una solicitud, pero al menos no obtienes una respuesta innecesaria.
Espero que esto ayude.
Si desea cancelar solicitudes pendientes en stateChangeStart con ui-router, puede usar algo como esto:
// en servicio
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;
// en la configuración de UIrouter
$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();
}
});
});