AngularJS отменяет все ожидающие $http запросы на изменение маршрута
Пожалуйста, сначала пройдите код
app.js
var app = angular.module('Nimbus', ['ngRoute']);
route.js
app.config(function($routeProvider) {
$routeProvider
.when('/login', {
controller: 'LoginController',
templateUrl: 'templates/pages/login.html',
title: 'Login'
})
.when('/home', {
controller: 'HomeController',
templateUrl: 'templates/pages/home.html',
title: 'Dashboard'
})
.when('/stats', {
controller: 'StatsController',
templateUrl: 'templates/pages/stats.html',
title: 'Stats'
})
}).run( function($q, $rootScope, $location, $route, Auth) {
$rootScope.$on( "$routeChangeStart", function(event, next, current) {
console.log("Started");
/* this line not working */
var canceler = $q.defer();
canceler.resolve();
});
$rootScope.$on("$routeChangeSuccess", function(currentRoute, previousRoute){
$rootScope.title = ($route.current.title) ? $route.current.title : 'Welcome';
});
})
дом-controller.js
app.controller('HomeController',
function HomeController($scope, API) {
API.all(function(response){
console.log(response);
})
}
)
Статс-controller.js
app.controller('StatsController',
function StatsController($scope, API) {
API.all(function(response){
console.log(response);
})
}
)
api.js
app.factory('API', ['$q','$http', function($q, $http) {
return {
all: function(callback) {
var canceler = $q.defer();
var apiurl = 'some_url'
$http.get(apiurl,{timeout: canceler.promise}).success(callback);
}
}
}]);
Когда я перехожу из дома в статистику, снова API отправляет http-запрос, у меня много таких http-вызовов, я вставил всего несколько строк кода.
Что мне нужно, так это то, что мне нужно отменить все отложенные запросы http на routechangestart или успешно
Или любой другой способ реализовать то же самое?
4 ответа
Я собрал некоторый концептуальный код для этого. Возможно, потребуется настроить в соответствии с вашими потребностями. Есть pendingRequests
сервис, который имеет API для добавления, получения и отмены запросов, httpService
это обертывания $http
и гарантирует, что все запросы отслеживаются.
Используя $http
Конфигурационный объект ( документы) мы можем получить способ отменить ожидающий запрос.
Я сделал plnkr, но вам понадобятся быстрые пальцы, чтобы увидеть, что запросы отменяются, поскольку тестовый сайт, который я обнаружил, обычно отвечает в течение полсекунды, но вы увидите на вкладке сети devtools, что запросы действительно отменяются. В вашем случае, вы бы явно вызвали cancelAll()
позвонить по соответствующим событиям из $routeProvider
,
Контроллер как раз для демонстрации концепции.
angular.module('app', [])
// This service keeps track of pending requests
.service('pendingRequests', function() {
var pending = [];
this.get = function() {
return 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.canceller.resolve();
});
pending.length = 0;
};
})
// This service wraps $http to make sure pending requests are tracked
.service('httpService', ['$http', '$q', 'pendingRequests', function($http, $q, pendingRequests) {
this.get = function(url) {
var canceller = $q.defer();
pendingRequests.add({
url: url,
canceller: canceller
});
//Request gets cancelled if the timeout-promise is resolved
var requestPromise = $http.get(url, { timeout: canceller.promise });
//Once a request has failed or succeeded, remove it from the pending list
requestPromise.finally(function() {
pendingRequests.remove(url);
});
return requestPromise;
}
}])
// The controller just helps generate requests and keep a visual track of pending ones
.controller('AppCtrl', ['$scope', 'httpService', 'pendingRequests', function($scope, httpService, pendingRequests) {
$scope.requests = [];
$scope.$watch(function() {
return pendingRequests.get();
}, function(pending) {
$scope.requests = pending;
})
var counter = 1;
$scope.addRequests = function() {
for (var i = 0, l = 9; i < l; i++) {
httpService.get('https://public.opencpu.org/ocpu/library/?foo=' + counter++);
}
};
$scope.cancelAll = function() {
pendingRequests.cancelAll();
}
}]);
Ты можешь использовать $http.pendingRequests
сделать это.
Во-первых, когда вы делаете запрос, сделайте это:
var cancel = $q.defer();
var request = {
method: method,
url: requestUrl,
data: data,
timeout: cancel.promise, // cancel promise, standard thing in $http request
cancel: cancel // this is where we do our magic
};
$http(request).then(.....);
Теперь мы отменяем все ожидающие запросы в $routeChangeStart
$rootScope.$on('$routeChangeStart', function (event, next, current) {
$http.pendingRequests.forEach(function(request) {
if (request.cancel) {
request.cancel.resolve();
}
});
});
Таким образом, вы также можете "защитить" определенный запрос от отмены, просто не предоставив поле "отменить" в запросе.
Я думаю, что это лучшее решение для отмены запросов. Он использует перехватчик и событие $routeChangeSuccess. http://blog.xebia.com/cancelling-http-requests-for-fun-and-profit/
Обратите внимание, что я новичок в Angular, так что это может быть неоптимально. Другое решение может быть следующим: при запросе $http, добавляющем аргумент "timeout", Docs, я сделал это следующим образом:
На фабрике, где я звоню всем своим службам отдыха, придерживайтесь этой логики.
module.factory('myactory', ['$http', '$q', function ($http, $q) {
var canceler = $q.defer();
var urlBase = '/api/blabla';
var factory = {};
factory.CANCEL_REQUESTS = function () {
canceler.resolve();
this.ENABLE_REQUESTS();
};
factory.ENABLE_REQUESTS = function () {
canceler = $q.defer();
};
factory.myMethod = function () {
return $http.get(urlBase, {timeout: canceler.promise});
};
factory.myOtherMethod= function () {
return $http.post(urlBase, {a:a, b:b}, {timeout: canceler.promise});
};
return factory;
}]);
и на угловой конфигурации приложения у меня есть:
return angular.module('app', ['ngRoute', 'ngSanitize', 'app.controllers', 'app.factories',
'app.filters', 'app.directives', 'ui.bootstrap', 'ngGeolocation', 'ui.select' ])
.run(['$location', '$rootScope', 'myFactory', function($location, $rootScope, myFactory) {
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
myFactory.CANCEL_REQUESTS();
$rootScope.title = current.$$route.title;
});
}]);
Таким образом, он перехватывает все изменения "маршрута" и останавливает все запросы, настроенные с помощью этого "таймера", чтобы вы могли выбрать то, что для вас критично.
Надеюсь, это кому-нибудь поможет. С уважением