如何在angularjs中等待直到响应来自$ http请求?


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中这样做吗?

Answers:


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()调用在.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秒来完成。如果该函数在此期间未返回任何内容,则它将有效地变为普通的同步代码,并将挂起浏览器直到完成。

尽管Promise会立即返回,但浏览器可以在此期间继续使用其他代码。一旦承诺解决/失败,就会触发then()调用。因此,即使它可能使您的代码流变得更复杂,这种方式也更加有意义(毕竟,复杂性通常是异步/并行编程的普遍问题!)


2
这解决了我的问题!!!对于其他任何人,我都有一个下拉列表,需要ajax调用中的数据,因此在创建范围时,数据不可用。通过这种延迟,可以将范围分配为具有来自ajax调用的数据。
Kat Lim Ruiz 2013年

8
@mikel:我在这里还有另一个问题。您的myFuction()调用将立即返回,但是该promise .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 2014年

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

很好的解决方案。当我看着它时,我也在沿着同样的思路思考。很高兴有人把它放在那里。
Nate

0

仅供参考,这是使用Angularfire,因此对于不同的服务或其他用途,它可能会有所不同,但应解决$ http具有的相同问题。对于同一问题,我有一个最适合我的解决方案,那就是将所有服务/工厂合并到范围内的单个承诺中。在需要加载这些服务/等的每条路线/视图上,我将需要加载数据的所有函数放入控制器函数中,即在我通过身份验证后运行的myfunct()和main 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​​时。无论如何,我希望这会有所帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.