Как дождаться ответа от запроса $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);
}
его работает нормально для меня, согласно моим требованиям. Но проблема здесь, когда я перезагрузки моего Webpage служба будет вызываться снова и запрашивать сервер. Если между какой-либо другой функцией выполняется, которая зависит от "определенной службы", это дает ошибку, как "что-то" не определено. Поэтому я хочу подождать в своем скрипте, пока служба не будет загружена. Как я могу это сделать? Есть ли вообще это в 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() не возвращался до тех пор, пока .тогда() функция завершает выполнение.
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()
не беспокоясь о проблемах асинхронных обещаний / заказа / очереди. Надеюсь, это поможет кому-то с теми же проблемами, что и у меня.