AngularJS에서 Ajax 요청이 주어졌습니다.
$http.get("/backend/").success(callback);
다른 요청이 시작된 경우 해당 요청을 취소하는 가장 효과적인 방법은 무엇입니까 (예 : 동일한 백엔드, 다른 매개 변수).
promise.abort()
stackoverflow.com/a/50415480/984780의
AngularJS에서 Ajax 요청이 주어졌습니다.
$http.get("/backend/").success(callback);
다른 요청이 시작된 경우 해당 요청을 취소하는 가장 효과적인 방법은 무엇입니까 (예 : 동일한 백엔드, 다른 매개 변수).
promise.abort()
stackoverflow.com/a/50415480/984780의
답변:
이 기능은 타임 아웃 매개 변수를 통해 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.
setTimeout
기능 또는 Angular의 $timeout
서비스를 사용하여 일정 시간이 지난 후 약속을 취소하도록 시간 초과를 설정할 수 있습니다 .
timeout 속성으로 Angular $ http Ajax를 취소하면 Angular 1.3.15에서 작동하지 않습니다. 이것을 고치기를 기다릴 수없는 사람들을 위해 Angular로 싸인 jQuery 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);
나중에 서비스에서 데이터를로드 할 때 $ http 대신 HttpService를 사용합니다.
(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);
$http
AngularJS의 현재 버전에서는 발행 된 요청의 취소가 지원되지 않습니다. 거기에있다 열 풀 요청 이 기능을 추가 할 수는 있지만이 AngularJS와 코어로 만들려고하는 경우가 삭제되지 않도록이 PR은 아직 검토되지 않았다.
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;
// 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();
}
});
});
request.timeout
이 존재 하는 이유를 알아야하는 이유는 무엇 입니까?
어떤 이유로 config.timeout이 작동하지 않습니다. 나는이 접근법을 사용했다 :
let cancelRequest = $q.defer();
let cancelPromise = cancelRequest.promise;
let httpPromise = $http.get(...);
$q.race({ cancelPromise, httpPromise })
.then(function (result) {
...
});
그리고 cancelRequest.resolve ()를 취소합니다. 실제로 요청을 취소하지는 않지만 최소한 불필요한 응답을받지는 않습니다.
도움이 되었기를 바랍니다.
{ cancelPromise, httpPromise }
십니까?
이것은 다음과 같이 중단 방법으로 $ 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 메소드를 호출하면 "지연"이 맵에서 검색된 다음 resolve 메소드를 호출하여 http 요청을 취소합니다.
이것이 누군가를 돕기를 바랍니다.
한계
현재 이것은 $ http.get에서만 작동하지만 $ http.post 등에 대한 코드를 추가 할 수 있습니다.
사용하는 방법 ...
그런 다음 예를 들어 다음과 같이 상태 변경시 사용할 수 있습니다 ...
rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
angular.forEach($http.pendingRequests, function (request) {
$http.abort(request);
});
});
다음은 여러 요청을 처리하는 버전이며 오류 블록의 오류를 억제하기 위해 콜백에서 취소 된 상태를 확인합니다. (타입 스크립트로)
컨트롤러 레벨 :
requests = new Map<string, ng.IDeferred<{}>>();
내 http에서 :
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(() => { });
}
도우미 방법
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';
}
이제 네트워크 탭을 보면 잘 작동합니다. 나는 방법을 4 번 호출했으며 마지막 방법 만 통과했습니다.
약속에 기능을 $http
추가하는 "데코레이터"를 사용 하여 서비스에 사용자 정의 기능을 추가 할 수 있습니다 abort()
.
작동 코드는 다음과 같습니다.
app.config(function($provide) {
$provide.decorator('$http', function $logDecorator($delegate, $q) {
$delegate.with_abort = function(options) {
let abort_defer = $q.defer();
let new_options = angular.copy(options);
new_options.timeout = abort_defer.promise;
let do_throw_error = false;
let http_promise = $delegate(new_options).then(
response => response,
error => {
if(do_throw_error) return $q.reject(error);
return $q(() => null); // prevent promise chain propagation
});
let real_then = http_promise.then;
let then_function = function () {
return mod_promise(real_then.apply(this, arguments));
};
function mod_promise(promise) {
promise.then = then_function;
promise.abort = (do_throw_error_param = false) => {
do_throw_error = do_throw_error_param;
abort_defer.resolve();
};
return promise;
}
return mod_promise(http_promise);
}
return $delegate;
});
});
이 코드는 angularjs의 데코레이터 기능을 사용 with_abort()
하여$http
서비스에 .
with_abort()
사용 $http
는 HTTP 요청을 취소 할 수 있습니다 옵션 타임 아웃.
반환 된 약속은 abort()
함수 를 포함하도록 수정되었습니다 . 또한 코드를 확인하여abort()
약속을 묶어도 작동 있습니다.
사용 방법의 예는 다음과 같습니다.
// your original code
$http({ method: 'GET', url: '/names' }).then(names => {
do_something(names));
});
// new code with ability to abort
var promise = $http.with_abort({ method: 'GET', url: '/names' }).then(
function(names) {
do_something(names));
});
promise.abort(); // if you want to abort
전화 할 때 기본적으로 abort()
요청하면 요청이 취소되고 약속 핸들러가 실행되지 않습니다.
오류 처리기를 호출하려면 true를 전달하십시오. abort(true)
.
오류 처리기에서 xhrStatus
속성 을 확인하여 "오류"가 "중단"으로 인한 것인지 확인할 수 있습니다 . 예를 들면 다음과 같습니다.
var promise = $http.with_abort({ method: 'GET', url: '/names' }).then(
function(names) {
do_something(names));
},
function(error) {
if (er.xhrStatus === "abort") return;
});