Как дождаться ответа от запроса $ http, в angularjs?
Я использую некоторые данные, которые из RESTful службы на нескольких страницах.
Поэтому я использую угловые фабрики для этого. Итак, мне нужно было получить данные один раз с сервера, и каждый раз, когда я получаю данные с этой определенной службой. Так же как и глобальные переменные. Вот пример:
var myApp = angular.module('myservices', []);
myApp.factory('myService', function($http) {
$http({method:"GET", url:"/my/url"}).success(function(result){
return result;
});
});
в моем контроллере я использую эту услугу как:
function myFunction($scope, myService) {
$scope.data = myService;
console.log("data.name"+$scope.data.name);
}
его работает нормально для меня в соответствии с моими требованиями.
Но проблема вот в чем, когда я перезагрузил в моей веб-странице служба будет вызывается снова и запрашивает сервер. Если между некоторыми другими функциями выполняется, которая зависит от" определенной службы", это дает ошибку, как" что-то " не определено. Поэтому я хочу подождать в своем скрипте, пока служба не будет загружена. Как я могу это сделать? Есть ли в любом случае сделать это в angularjs?
4 ответов:
вы должны использовать обещания для асинхронных операций, когда вы не знаете, когда он будет завершен. Обещание "представляет собой операцию, которая еще не завершена, но ожидается в будущем."(https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise)
пример реализации будет выглядеть так:
myApp.factory('myService', function($http) { var getData = function() { // Angular $http() and then() both return promises themselves return $http({method:"GET", url:"/my/url"}).then(function(result){ // What we return here is the data that will be accessible // to us after the promise resolves return result.data; }); }; return { getData: getData }; }); function myFunction($scope, myService) { var myDataPromise = myService.getData(); myDataPromise.then(function(result) { // this is only run after getData() resolves $scope.data = result; console.log("data.name"+$scope.data.name); }); }Edit: что касается Sujoys комментарий, что Что мне нужно сделать, чтобы myFuction () call не возвращался до тех пор, пока .тогда() функция завершает выполнение.
function myFunction($scope, myService) { var myDataPromise = myService.getData(); myDataPromise.then(function(result) { $scope.data = result; console.log("data.name"+$scope.data.name); }); console.log("This will get printed before data.name inside then. And I don't want that."); }ну, предположим, что вызов getData () занял 10 секунд. Если бы функция ничего не возвращала за это время, она фактически стала бы обычным синхронным кодом и повесила бы браузер до его завершения.
с обещанием возвращения мгновенно, хотя, браузер может свободно продолжать с другим кодом в то же время. Как только обещание разрешает/терпит неудачу, вызов then() запускается. Так что это имеет гораздо больше смысла, даже если это может сделать поток вашего кода немного более сложным (сложность-это общая проблема асинхронного / параллельного программирования в целом!)
для людей, незнакомых с этим, вы также можете использовать обратный вызов, например:
в номере:
.factory('DataHandler',function ($http){ var GetRandomArtists = function(data, callback){ $http.post(URL, data).success(function (response) { callback(response); }); } })в вашем контроллере:
DataHandler.GetRandomArtists(3, function(response){ $scope.data.random_artists = response; });
у меня была та же проблема, и ни один, если они работали для меня. Вот что действительно сработало...
app.factory('myService', function($http) { var data = function (value) { return $http.get(value); } return { data: data } });и тогда функция, которая его использует...
vm.search = function(value) { var recieved_data = myService.data(value); recieved_data.then( function(fulfillment){ vm.tags = fulfillment.data; }, function(){ console.log("Server did not send tag data."); }); };сервис не является необходимым, но я думаю,что это хорошая практика для расширения. Большая часть того, что вам понадобится по одному для любой другой, особенно когда с помощью API. В любом случае, я надеюсь, это было полезно.
FYI, это использует Angularfire, поэтому он может немного отличаться для другого сервиса или другого использования, но должен решить тот же isse $http. У меня был этот же вопрос только решение, которое подходит для меня лучше всего было объединить все услуги/фабрики в одном обещании по объему. На каждом маршруте / представлении, которое нуждалось в загрузке этих сервисов / etc, я помещаю любые функции, которые требуют загруженных данных внутри функции контроллера, т. е. myfunct() и основного приложения.JS на запуска после авторизации я положил
myservice.$loaded().then(function() {$rootScope.myservice = myservice;});и в представлении я только что сделал
ng-if="myservice" ng-init="somevar=myfunct()"в первом / родительском элементе представления / оболочке, чтобы контроллер мог запускать все внутри
myfunct()не беспокоясь о проблемах с асинхронными обещаниями / заказами / очередями. Я надеюсь, что это поможет кому-то с теми же проблемами, что и у меня.
Comments