web-dev-qa-db-ja.com

angularjsで、応答が$ http要求から来るまで待つ方法は?

RESTfulサービスからのデータを複数のページで使用しています。だから私はそのために角工場を使用しています。そのため、サーバーからデータを1回取得する必要があり、その定義済みサービスを使用してデータを取得するたびに必要になります。グローバル変数と同じです。これがサンプルです。

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

それは私の要件に従って私のためにうまく働いています。しかし、ここでの問題は、私が自分のWebページにリロードしたときに、サービスが再度呼び出されてサーバーを要求することです。 「定義済みサービス」に依存している他の関数が実行されている間に、「何か」が定義されていないようなエラーを出している場合。だから私はサービスがロードされるまで私のスクリプトで待ちたいです。どうやってやるの?とにかくそれはangularjsにありますか?

88
anilCSE

いつ完了するかわからない非同期操作にはpromiseを使用してください。約束は「まだ完了していない操作を表しますが、将来的に期待されています」。 ( 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についてコメントして Mythen()関数が実行を終了するまで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()呼び出しがトリガーされます。そのため、コードの流れがもう少し複雑になる可能性がある場合でも、このようにしてはるかに意味があります(結局、複雑さは非同期/並列プログラミングの一般的な問題です)。

146
mikel

これに慣れていない人のためには、例えばコールバックを使うこともできます。

あなたのサービスでは:

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

参考までに、これはAngularfireを使用しているため、サービスやその他の用途によって多少異なる場合がありますが、$ httpが持っているのと同じ問題を解決する必要があります。私は、同じ問題を私に最も適した唯一の解決策として、すべてのサービス/工場を範囲内の単一の約束に結合することでした。これらのサービスなどをロードする必要がある各ルート/ビューで、ロード後のデータを必要とするすべての関数、つまりmyfunct()とメインのapp.jsを認証後に実行します。

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

そして私がした見解では

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

最初の/ parentビュー要素/ラッパー内にあるので、コントローラは内部ですべてを実行できます。

myfunct()

非同期の約束/順序/キューの問題を心配することなく。私はそれが私が持っていたのと同じ問題を抱えている誰かに役立つことを願っています。

0
Samuel Barney

私は同じ問題を抱えていました、そして、これらが私のために働いたならば何もありません。これはうまくいったことですが...

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を使用している場合は、必要とするもののほとんどは他のものにも役立ちます。とにかく私はこれが参考になったと思います。

0
user3127557