94

複数のページで 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);
}

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

4

4 に答える 4

151

いつ完了するかわからない非同期操作には promise を使用する必要があります。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);
    });
}

編集: .then() 関数が実行を終了するまで myFuction() 呼び出しが返されないようにするために何をする必要があるかというSujoys のコメントについて。

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 はすぐに返されるため、その間、ブラウザは自由に他のコードを続行できます。promise が解決/失敗すると、 then() 呼び出しがトリガーされます。したがって、コードの流れがもう少し複雑になる可能性があるとしても、この方法ははるかに理にかなっています (結局のところ、複雑さは一般的に非同期/並列プログラミングの一般的な問題です!)

于 2013-08-24T19:01:22.173 に答える
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;
   });
于 2014-07-06T02:59:03.253 に答える
1

私は同じ問題を抱えていましたが、これらがうまくいった場合は問題ありませんでした。ここでうまくいったのは...

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 を使用する場合は、1 つに必要なもののほとんどが他のものにも当てはまります。とにかく、これがお役に立てば幸いです。

于 2015-07-06T23:25:15.413 に答える
0

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

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

そして、私がしたばかりのビューで

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

最初/親のビュー要素/ラッパーで、コントローラーが内部のすべてを実行できるようにします

myfunct()

非同期の約束/注文/キューの問題を心配する必要はありません。私が抱えていたのと同じ問題を抱えている人に役立つことを願っています。

于 2015-11-11T22:31:02.517 に答える