1

更新2: これはより良い説明だと思います:

2つのコールバックがあり、それぞれが配列を埋めています。どういうわけかこれらの配列をマージしたいと思います。これを行うための単純な方法は、配列がいっぱいになるまで待ってから、forループでマージすることです。コールバックが「完了」したかどうかを確認する実際の方法がないため、これを行うことはできません。

次のステップは次のようになります。オブジェクトがコールバックによってダウンロードされるたびに、マージ配列(混合と呼ばれる)をチェックし、「パートナー」オブジェクトが含まれているかどうかを確認します。含まれている場合:次に、そのパートナーオブジェクトにマージします。そうでない場合は、そのオブジェクトを挿入します。

競合状態が心配です。コールバック1は配列が空であることを確認し、配列に挿入することを決定しますが、コントロールは最初に挿入するコールバック2に切り替わります。コールバック1は挿入ではなくマージする必要がありますが、コントロールが元に戻ると、代わりに挿入されます。

コードのアトミックな「チェックと挿入/マージ」ブロックを作成できれば、役立つ可能性があります。それを行う方法はありますか?


アップデート1: コードとさらに多くの単語が追加されました!

みなさん、お返事ありがとうございます。私は行って、コードをできるだけ単純化しようとしました。

言葉:

混合という配列があります。混合は、最終的に次のようになります。タイプ(A)のすべてのオブジェクト、およびタイプ(B)のアナログオブジェクト(「プライベート」とも呼ばれます)がある場合は、それらをマージする必要があります。

これは、コールバックを使用する2つの関数getAllAとgetAllBを使用することを意味します。今、私は両方を呼び出し、少し手動で待ってから、そのマージを行うforループを実行します。

私がする必要があるのは、コールバックでマージが行われるようにコードを編集することです。ただし、競合状態を作成しない方法でマージする方法は考えられません。

素朴に、私は最初にタイプAのオブジェクトと混合して埋め、次にBオブジェクトを反復処理し、必要に応じてそれらをマージしたいと思うかもしれません。ただし、Firebaseでon( "contact_added")を使用して「完了」したかどうかを確認する方法がないため、これを行うことはできません。並行配列構造が欲しいと思いますが、組み込みの配列の使い方がわかりません。自分で作ったのかどうかを確認する方法がわからないので、自分で作るのが心配です。競合状態はそのように注意が必要です。

ここで、コード: 参照する必要のあるスクリプトは次のとおりです。

そして、これが私がjavascriptコンソールに貼り付けるものです:

    //Note: private ~~ B
    //      public ~ A

    var me = 'IWwypRHWpDmydd30o-v';
    var mixed = new Array();
    var mixedNames = new Array();
    var privates = new Object();

    var callbackB = function(snapshot){
        child = snapshot.val();
        privates[snapshot.name()] = child;
    };

    var callbackA = function(snapshot){
        var listRef = snapshot.ref();
        listRef.on('child_added', function (snapshot2) {
        child = snapshot2.val();
            mixedNames.push(snapshot2.name());
            mixed.push(child);
      });
    };

    var getAllB = function (callback, ownerid){
        var priv = new Firebase('http://gamma.firebase.com/innermost/project/private/' + ownerid);
        priv.on('child_added', function (snapshot){
        callback(snapshot);
      });
    };

    function getAllA(callback) {
      var pub = new Firebase('http://gamma.firebase.com/innermost/project/public');
      pub.once('value', function (snapshot) {
        if (snapshot.val() === null) {
          alert('snapshot does not exist.');
        }
        callback(snapshot);
      });
    }

    getAllA(callbackA);
    getAllB(callbackB, me);

    //////wait

    for (b in privates){
        var index = $.inArray(b, mixedNames);
        if (index < 0){ //if there is no record with this name
            mixed.push(privates[b]);
            mixedNames.push(b);
        }
        else{
            var pub = mixed[index];
            var mutt = returnMixed(pub, privates[b]);
            mixed.splice(index,1,mutt);
        }
    };

私がやりたいのは、ロジックをforループからコールバックに移動することです。forループをすぐに実行すると、配列はまだコールバックを介してダウンロードされないためです。


古いエントリ:

Firebaseのデータリストにアクセスする2つのコールバックがあります。

コールバック1はタイプAのオブジェクトを取得します。コールバック2はタイプBのオブジェクトを取得します。

私の目標は、タイプAとタイプBのオブジェクトを適切にマージする配列を用意することです。

タイプBのほとんどの(ただし必然的にすべての)オブジェクトには、タイプAの「パートナー」オブジェクトがあります。タイプAのいくつかのオブジェクトには、タイプBのパートナーオブジェクトがあります。

Firebaseから取得したオブジェクトごとに、パートナーが配列に含まれているかどうかを確認したいと思います。そうでない場合は、挿入します。その場合は、代わりにパートナーと「マージ」します。

同時データ構造なしでこれを行う方法を考えることはできませんが、Javascriptでそれを行う方法がわかりません。

どうすればその並行配列を作成できますか、または他の方法で目標を達成する方法を見つけることができますか?

4

4 に答える 4

2
<script src="underscore.js"></script> <!-- or the lib of your choice -->
<script>

   function addWithPartner( value, id, type ) {
      var indexOfPartner = _.find(values, function(partner, i) {
         // logic for determining what a partner is goes here
         // for example: 
         return value.name == partner.name;
      });

      if( indexOfPartner >= 0 ) {
         merge( values, indexOfPartner, value );
      }
      else {
         values.push( value );
      }
   }

   function merge( list, index, value ) {
      // do whatever merge means here
      // for example:
      _.extend( list[index], value );
   }

   var FB = new Firebase(YOUR_URL);
   var values = [];

   FB.child('TYPEA').on('child_added', function(snapshot) {
      addWithPartner( snapshot.val(), snapshot.name(), 'typeA' );
   });

   FB.child('TYPEB').on('child_added', function(snapshot) {
      addWithPartner( snapshot.val(), snapshot.name(), 'typeB' );
   });

</script>
于 2012-08-09T01:45:12.870 に答える
1

JSの値はゼロですよね?とにかく、そうでなければ、この答えは役に立たない。

私がすることは、オブジェクトを渡し、そのパートナーが配列内にあるかどうかを確認する関数をメイン配列に持つことです。そうである場合は、そのオブジェクトを返します。そうでない場合は、nilを返します。このようにして、必要に応じてマージを実行するオブジェクトがすでにあります。

さらに、あなたがそれをどのように表現したかについては正確にはわかりませんでしたが、並行性が問題になること(競合状態、上書きなど)について心配していたようですか?その場合、これはミューテックスを使用する場所の完璧な例です(jsにミューテックスがない場合は、かなり簡単に作成できます)。上記の機能を最初にロックし、最後にロックを解除するだけで、古いデータの読み取りを回避できます。お役に立てば幸いです。

于 2012-08-08T23:41:27.453 に答える
1

質問の詳細を100%理解しているとは限りませんが、JavaScriptがシングルスレッドであるため、真の同時実行性について心配する必要がないことを知っておくと役立つ場合があります。コールバックは常に一度に1つずつ発生します。

したがって、「同時データ構造」は必要ありません。javascriptには同時実行性がないため、ほとんどの場合、どのデータ構造でも機能します。:-)

于 2012-08-09T00:40:57.597 に答える
0

Like explained in earlier answers, javascript is single threaded when limited to the main window; even if a function is called asychronously, its execution will be "atomic" (not interrupted). Thus you can't have race conditions.

However, dealing with the problem " I can't do that because there's no real way to check if the callbacks are "done"", try http://www.megiddo.ch/jcon-q-rency that provides a wait/notify(All) mechanism. I use it to do operations quite like yours.

With it, you can delay the execution of a function until a certain condition is satisfied. That is your "//////wait". When getAllA() and getAllB() are done, they can notify a waiting function that is in charge of executing the for (b in privates){..} loop.

于 2012-08-31T13:43:58.023 に答える