Як чекати, поки відповідь надійде із запиту $ http у angularjs?


93

Я використовую деякі дані, які є послугою 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?

Відповіді:


150

Вам слід використовувати обіцянки для асинхронних операцій, коли ви не знаєте, коли це буде виконано. Обіцянка "являє собою операцію, яка ще не завершена, але очікується в майбутньому". ( 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 () не повернувся до .the () функція завершує виконання.

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 секунд для завершення. Якщо за цей час функція нічого не повертає, вона фактично стає звичайним синхронним кодом і зависає в браузері до завершення.

Хоча обіцянка повертається миттєво, браузер тим часом може продовжувати роботу з іншим кодом. Після того, як обіцянка вирішена / не виконана, викликається тоді () виклик. Тому це має набагато більше сенсу, навіть якщо це може зробити потік вашого коду трохи складнішим (складність - це загальна проблема асинхронного / паралельного програмування взагалі!)


2
Це вирішило моє питання !!! Для всіх інших у мене було спадне меню, яке потребувало даних з виклику ajax, тому коли створено область, дані були недоступні. За допомогою цього відстрочки може бути призначено область, щоб мати дані, що надходять від виклику ajax.
Kat Lim Ruiz

8
@mikel: У мене тут ще одне питання. Ваш виклик myFuction () повернеться негайно, але ця обіцянка .then () зателефонує пізніше. Що мені потрібно зробити, щоб виклик 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."); }
Sujoy

13

для людей, які не знайомі з цим, ви також можете використовувати зворотний дзвінок, наприклад:

До ваших послуг:

.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;
   });

Чудове рішення. Думав по цій же лінії, коли я розглядав це. Радий, що хтось виклав це там.
Нейт

0

FYI, для цього використовується Angularfire, тому він може дещо відрізнятися для іншої послуги чи іншого використання, але повинен вирішити той самий isse $ http. У мене було одне і те саме рішення, яке найкраще підходило для мене - поєднати всі послуги / фабрики в єдину обіцянку щодо сфери застосування. На кожен маршрут / перегляд, який потребував завантаження цих служб / тощо, я розміщував будь-які функції, які вимагають завантаження даних всередині функції контролера, тобто myfunct () та головного app.js, запущеного після авт

myservice.$loaded().then(function() {$rootScope.myservice = myservice;});

і на вигляд я щойно зробив

ng-if="myservice" ng-init="somevar=myfunct()"

в першому / батьківському елементі перегляду / обгортці, щоб контролер міг працювати все всередині

myfunct()

не турбуючись про проблеми асинхронізації / замовлення / черги. Я сподіваюся, що це допомагає комусь із тих самих питань, що і я.


0

У мене були ті ж проблеми, і жодна, якщо вони працювали на мене. Ось що зробило, хоча ...

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. У будь-якому випадку я сподіваюся, що це було корисно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.