2016-11-19 5 views
2

私は、FirebaseとangularJSを使用してユーザーのリストを取得しています。私はonce()機能と私のデータベースからすべてのユーザーを読み取ることができますが、私はusersの処理を行っていますまで、userListリターンは私が私のuserList変数を割り当てるために待つonce()関数の外部でFirebaseがリファレンスを失うのはなぜですか?

.service('userService', [function() { 
    this.getUsers = function() { 
     var users; 
     var userList; 
     var ref = firebase.database().ref('/users/'); 
     ref.once('value').then(function(snapshot) { 
      users = snapshot.val(); 
      for(var key in users) { 
       users[key].id = key; 
       // do some other stuff 
      } 
      console.log(users); // outputs all users 
     }).then(function(){ 
      userList = users; 
      console.log(userList); // outputs all users 
     },(function(error){ 
      alert('error: ' + error); 
     }); 
     console.log(userList); // outputs 'undefined' 
    } 
}]); 

下に未定義なぜ私は理解できない、ありません運。

ここで重要なことがありますが、私は約束/コールバックに関する問題があり、ドキュメントでそれを見つけることができません。誰かが私の問題を理解するのを助けることができますか

答えて

1

あなたは非同期を考える必要があります。

.service('userService', [function() { 
    this.getUsers = function() { 
     var users; 
     var ref = firebase.database().ref('/users/'); 

     <!-- this happens ASYNC --> 
     ref.once('value', function(snapshot) { 
      users = snapshot.val(); 
      for(var key in users) { 
       users[key].id = key; 
       // do some other stuff 
      } 
      console.log(users); // outputs all users 
     },function(error){ 
      alert('error: ' + error); 
     }); 
     <!-- end async action --> 

     console.log(users); // outputs 'undefined' 
    } 
}]); 

私はあなたがこれをしなかった場合、あなたは大丈夫だろう賭け:

.service('userService', [function() { 
    this.getUsers = function() { 
     var users; 
     var ref = firebase.database().ref('/users/'); 

     <!-- this happens ASYNC --> 
     ref.once('value', function(snapshot) { 
      users = snapshot.val(); 
      for(var key in users) { 
       users[key].id = key; 
       // do some other stuff 
      } 
      console.log(users); // outputs all users 
     },function(error){ 
      alert('error: ' + error); 
     }); 
     <!-- end async action --> 

     window.setTimeout(function() { 
      console.log(users); // outputs 'undefined' 
     }, 1500); 
    } 
}]); 

フランクさんのコメントあたりの明確化:

私はさらに明確にすべきsetTimeoutはこれがタイミングの問題であることを証明するに過ぎません。あなたのアプリケーションでsetTimeoutを使用している場合、おそらくnミリ秒間信頼できる結果を待つことができないので、悪い時が来るでしょう。コールバックを発したり、スナップショットを取得した後で約束を解決する必要があります。データ。

+0

私の非同期関数が正常に完了した後に 'userList'をポピュレートするためのロジックを追加しました –

+2

' setTimeout() 'がうまく動作しないかもしれません(ほとんどの場合ネットワーク遅延に依存します)しかし、この問題の解決策は決して**まったくありません。正しい解決策は、 'users'リストを必要とするコードをコールバック/ブロックに移動することです。 –

4

Firebaseからデータを非同期的に読み取るのが問題です(imjaredという)。したがって、コードはあなたが思う順序で実行されません。

.service('userService', [function() { 
    this.getUsers = function() { 
     var ref = firebase.database().ref('/users/'); 
     console.log("before attaching listener"); 
     ref.once('value').then(function(snapshot) { 
      console.log("got value"); 
     }); 
     console.log("after attaching listener"); 
    } 
}]); 

はこれの出力は次のようになります:

が得たリスナー取り付けた後、リスナー

を取り付ける前に、それはちょうど少数のログステートメントでそれを簡略化することにより、それを見るのが一番簡単です値

注文を知るリスナーを取り付けた直後にユーザーリストを印刷できない理由を完全に説明する必要があります。解決のための今すぐHow do I return the response from an asynchronous call?

:いない場合は、私はこの偉大な答えを読んでも、お勧めしますがいずれかは、コールバックにユーザリストを使用する必要があるか約束を返します。コールバックにユーザリストを必要とするすべてのコードを移動:

これは非同期コードに対処する最古の方法でコールバックで

をユーザリストを使用してください。

ref.once('value', function(snapshot) { 
     users = snapshot.val(); 
     for(var key in users) { 
      users[key].id = key; 
     } 
     console.log(users); // outputs all users 
    }) 

あなたは、「ユーザリストがロードされるたびに、その内容を印刷する」「その内容を印刷し、最初のロードユーザーリスト」から、あなたのコードをリフレーミングしています。定義の違いは軽微ですが、突然あなたは完全に非同期の読み込みに対処できます。

あなたのコードで行うようにあなたはまた、約束と同じ操作を行うことができます。

ref.once('value').then(function(snapshot) { 
     users = snapshot.val(); 
     for(var key in users) { 
      users[key].id = key; 
      // do some other stuff 
     } 
     console.log(users); // outputs all users 
    }); 

しかし、約束を使用して、直接、コールバックを使用しての上で1つの巨大な利点があります:あなたが約束を返すことができます

戻る約束

多くの場合、あなたはgetUsers()機能にユーザーを必要とするすべてのコードを配置するとは思わないだろう。その場合、あなたはどちらかは(私はここでは表示されませんこれは、それはあなたがonce()に渡すことができますコールバックと非常に似ています)getUsers()にコールバックを渡すことができますまたはあなたはgetUsers()から約束を返すことができます。

this.getUsers = function() { 
    var ref = firebase.database().ref('/users/'); 
    return ref.once('value').then(function(snapshot) { 
     users = snapshot.val(); 
     for(var key in users) { 
      users[key].id = key; 
      // do some other stuff 
     } 
     return(users); 
    }).catch(function(error){ 
     alert('error: ' + error); 
    }); 
} 
このサービスで

、我々は今getUsers()を呼び出し、それらがロードされていたら、ユーザーを取得するために結果の約束を使用することができます。

userService.getUsers().then(function(userList) { 
    console.log(userList); 
}) 

をということで、あなたは非同期の獣を飼いならしています。まあ、今は少なくとも。これは、熟練したJavaScript開発者でさえもしばらくの間混乱させてしまうので、慣れるまでに時間がかかっても心配しないでください。

関連する問題