鑑於AngularJS
$http.get("/backend/").success(callback);
是什麼,如果另一個請求啓動(相同的後端,比如不同的參數)以取消該請求的最有效的方式Ajax請求。
鑑於AngularJS
$http.get("/backend/").success(callback);
是什麼,如果另一個請求啓動(相同的後端,比如不同的參數)以取消該請求的最有效的方式Ajax請求。
此功能是通過一個超時參數added to the 1.1.5 release:
var canceler = $q.defer();
$http.get('/someUrl', {timeout: canceler.promise}).success(successCallback);
// later...
canceler.resolve(); // Aborts the $http request if it isn't finished.
如果我需要通過承諾暫停和手動取消,我應該怎麼做? –
@RamanChodźka你可以做一個承諾,您可以設置一個超時時間,以便在一段時間後取消承諾,無論是使用JavaScript的本地'setTimeout'函數還是使用Angular的'$ timeout'服務。 –
非常感謝!我之前的解決方案只是使用jQuery來處理Ajax請求,而我真的很想避免這種情況。 – mirichan
當前版本的AngularJS不支持取消$http
發出的請求。有一個pull request opened來增加這個功能,但是這個PR還沒有被審查,所以目前還不清楚它是否會把它變成AngularJS的核心。
PR被拒絕,OP提交更新一個在這裏 https:// github.com/angular/angular.js/pull/1836 –
而且這也被關閉了。 – frapontillo
它的一個版本[https://github.com/angular/angular.js/commit/9f4f5937112655a9881d3281da8e72035bc8b180]。仍試圖找出使用最終版本的語法。祝願PR攜帶使用樣品! :) – SimplGy
取消角$ HTTP阿賈克斯與超時財產角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);
在服務以後,當你加載數據你會使用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);
如果要取消等待與UI的路由器上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();
}
});
});
這對我很有幫助 - 非常簡單,我添加了另一個名稱的呼叫,所以我可以選擇呼叫,只取消一些呼叫 –
爲什麼UI路由器配置需要知道'request.timeout'是否存在? – trysis
這增強用如下的方法中止裝飾$ 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);
});
});
我正在製作一個應用程序,它可以同時觸發一些http請求,我需要手動將它們全部中止。我試過你的代碼,但它只會中止最後的請求。那之前是否發生過這種事?任何幫助,將不勝感激。 –
此處的代碼維護對延遲對象的引用查找,以便稍後可以檢索它們,因爲要求延遲對象執行中止。查找重要的是關鍵:值對。該值是延遲對象。關鍵是基於請求方法/ url生成的字符串。我猜你正在中止多個請求到相同的方法/網址。因爲所有的鍵都是相同的,所以它們在地圖上相互覆蓋。您需要調整密鑰生成邏輯,以便即使URL /方法相同也會生成唯一的邏輯。 – danday74
繼續從上面...這不是在代碼中的錯誤,代碼處理中止多個請求...但代碼根本就沒有打算處理使用相同的http方法中止多個請求到同一個url ...但如果你調整邏輯,你應該能夠相當容易地運作。 – danday74
由於某種原因config.timeout不適合我。我用這個方法:
let cancelRequest = $q.defer();
let cancelPromise = cancelRequest.promise;
let httpPromise = $http.get(...);
$q.race({ cancelPromise, httpPromise })
.then(function (result) {
...
});
而且cancelRequest.resolve()取消。其實它並不是取消一個請求,但你至少沒有得到不必要的迴應。
希望這會有所幫助。
您是否看到過SyntaxError'{cancelPromise,httpPromise}'? – Mephiztopheles
這是ES6語法,你可以嘗試{c:cancelPromise,h:httpPromise} –
我看到,對象短初始化程序 – Mephiztopheles
這是一個處理多個請求的版本,它還檢查回調中的取消狀態以抑制錯誤塊中的錯誤。 (以打字稿)
控制器級別:
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請求離開瀏覽器,就無法取消它。下面的所有答案都以某種方式簡單地告訴了聽衆。 HTTP請求仍然會觸發服務器,仍然處理完畢,服務器仍然會發送響應,這只是客戶端仍在響應或不響應的一個案例。 – Liam
$ http請求取消路由更改http://www.freakyjolly.com/how-to-cancel-http-requests-in-angularjs-app/ –