รับคำขอ Ajax ใน AngularJS
$http.get("/backend/").success(callback);
วิธีที่มีประสิทธิภาพมากที่สุดในการยกเลิกคำขอนั้นคือถ้ามีการเปิดตัวคำขออื่น (เช่นแบ็กเอนด์เดียวกันพารามิเตอร์ที่แตกต่างกัน)
promise.abort()
stackoverflow.com/a/50415480/984780
รับคำขอ Ajax ใน AngularJS
$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
ฟังก์ชันดั้งเดิมของ JavaScript หรือ$timeout
บริการของ Angular
การยกเลิก Angular $ http Ajax ด้วยคุณสมบัติการหมดเวลาใช้งานไม่ได้ใน Angular 1.3.15 สำหรับผู้ที่ไม่สามารถรอให้สิ่งนี้ได้รับการแก้ไขฉันกำลังแบ่งปันโซลูชัน jQuery Ajax ที่ห่อด้วย Angular
การแก้ปัญหาเกี่ยวข้องกับสองบริการ:
ต่อไปนี้คือบริการ 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);
การยกเลิกคำขอที่ออกด้วย$http
ไม่รองรับกับเวอร์ชันปัจจุบันของ AngularJS มีคำขอดึงที่เปิดเพื่อเพิ่มความสามารถนี้ แต่ PR นี้ยังไม่ได้รับการตรวจสอบดังนั้นจึงไม่ชัดเจนว่ามันจะทำให้มันเข้าไปในแกน AngularJS
หากคุณต้องการยกเลิกคำขอที่รอดำเนินการใน stateChangeStart ด้วย ui-router คุณสามารถใช้สิ่งนี้:
// อยู่ในการให้บริการ
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 config
$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 รหัสจะเพิ่มการหมดเวลา "สัญญา" (หากตั้งค่าการหมดเวลาแล้วจะไม่มีการเปลี่ยนแปลงใด ๆ )
อย่างไรก็ตามเพื่อแก้ไขสัญญาที่เราต้องการจัดการกับ "รอการตัดบัญชี" เราจึงใช้แผนที่เพื่อให้เราสามารถเรียกข้อมูล "รอการตัดบัญชี" ได้ในภายหลัง เมื่อเราเรียกวิธีการยกเลิกจะมีการเรียก "รอการตัดบัญชี" จากแผนที่จากนั้นเราเรียกวิธีแก้ไขเพื่อยกเลิกการร้องขอ http
หวังว่านี่จะช่วยใครซักคน
ข้อ จำกัด
ปัจจุบันนี้ใช้งานได้กับ $ http.get เท่านั้น แต่คุณสามารถเพิ่มรหัสสำหรับ $ http.post และอื่น ๆ ได้
วิธีใช้ ...
จากนั้นคุณสามารถใช้มันตัวอย่างเช่นในการเปลี่ยนสถานะดังนี้ ...
rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
angular.forEach($http.pendingRequests, function (request) {
$http.abort(request);
});
});
นี่คือรุ่นที่จัดการคำขอหลายรายการรวมทั้งตรวจสอบสถานะที่ถูกยกเลิกในการติดต่อกลับเพื่อระงับข้อผิดพลาดในบล็อกข้อผิดพลาด (ใน typescript)
ระดับตัวควบคุม:
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()
คำขอจะถูกยกเลิกและไม่มีการเรียกใช้ตัวจัดการสัญญา
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;
});