Как подождать, пока ответ поступит из запроса $http, в angularjs?
Я использую некоторые данные из службы RESTful на нескольких страницах.
Поэтому для этого я использую заводы angular. Поэтому мне нужно было получить данные один раз с сервера, и каждый раз, когда я получаю данные с этим определенным сервисом. Точно так же, как глобальные переменные. Вот пример:
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);
}
Его работа прекрасна для меня в соответствии с моими требованиями.
Но проблема здесь в том, что когда я перезагружаюсь на своей веб-странице, служба снова будет вызвана и будет запрашиваться сервер. Если между ними выполняется какая-то другая функция, которая зависит от "определенной службы", она дает ошибку, как "что-то", undefined. Поэтому я хочу подождать в моем script до загрузки сервиса. Как я могу это сделать? Так или иначе, в angularjs?
Ответы
Ответ 1
Вы должны использовать promises для операций async, где вы не знаете, когда это будет завершено. Обещание "представляет собой операцию, которая еще не завершена, но ожидается в будущем". (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);
});
}
Изменить: Что касается комментария Sujoys, что
Что мне нужно сделать, чтобы вызов myFuction() не возвращался до тех пор, пока функция .then() не завершит выполнение.
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(). Таким образом, это имеет гораздо больший смысл, даже если это может сделать поток вашего кода немного более сложным (сложность - это общая проблема асинхронного/параллельного программирования вообще!)
Ответ 2
для новых пользователей, вы также можете использовать обратный вызов, например:
В вашем сервисе:
.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;
});
Ответ 3
У меня была такая же проблема, и нет, если бы они работали на меня. Вот что работало, хотя...
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. В любом случае, я надеюсь, что это было полезно.
Ответ 4
FYI, это использование Angularfire, поэтому он может немного отличаться для другой службы или другого использования, но должен решить тот же isse $http. У меня было то же самое решение, единственное решение, которое подходит мне лучше всего, чтобы объединить все сервисы/фабрики в единое обещание по сфере применения. На каждом маршруте/просмотре, в котором эти сервисы /etc были загружены, я помещал любые функции, которые требуют загруженных данных внутри функции контроллера, то есть myfunct() и main app.js при запуске после того, как auth я положил
myservice.$loaded().then(function() {$rootScope.myservice = myservice;});
и в представлении, которое я только что сделал
ng-if="myservice" ng-init="somevar=myfunct()"
в первом/родительском элементе/обертке, чтобы контроллер мог запускать все внутри
myfunct()
не беспокоясь о проблемах async promises/order/queue. Я надеюсь, что это поможет кому-то с теми же проблемами, что и я.