如何处理在javascript中访问数据结构的两个回调?

时间:2012-08-08 23:25:04

标签: javascript concurrency callback firebase

更新2: 我认为这是一个更好的解释:

我有两个回调,每个都填满一个数组。我想以某种方式合并这些数组。天真的方法是等待数组填充,然后与for循环合并。我不能这样做,因为没有真正的方法来检查回调是否“完成”。

下一步可能是这样的:每次通过回调下载对象时,它都会检查合并数组(称为混合),并查看它是否包含“伙伴”对象。如果是:那么合并到该伙伴对象。如果没有,则插入该对象。

我担心竞争条件:回调1看到数组是空的,决定插入它,但是然后控制切换到回调2,首先插入。回调1现在应该合并而不是插入,但是当控制切换回来时,它会插入。

如果我可以制作原子“检查并插入/合并”代码块,那么可能会有什么帮助。有没有办法做到这一点?


更新1: 现在有了代码,还有更多的单词!

感谢大家的回复。我去尝试尽可能地简化代码。

词:

我有一个名为mixed的数组。 Mixed应该以​​:(A)类型的所有对象,如果它们具有类型(B)的模拟对象(也称为“私有”),它们应该合并。

这意味着使用两个使用回调的函数 - 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上的数据列表。

回调1获取A类对象。 回调2获取类型为B的对象。

我的目标 - 拥有一个正确合并A类和B类对象的数组。

B类型的大多数(但必然是所有)对象都有一个A类型的“伙伴”对象。 A类的一些对象具有类型B的伙伴对象。

对于从Firebase中提取的每个对象,我想查看他们的伙伴是否在阵列中。如果没有,那么插入。如果是,则改为与合作伙伴“合并”。

如果没有并发数据结构,我无法想到这样做的方法 - 但我不知道如何在Javascript中这样做。

我如何创建并发数组,或者想办法以其他方式实现我的目标?

4 个答案:

答案 0 :(得分: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>

答案 1 :(得分:1)

JS有零值,对吧?无论如何,如果他们不这样做,这个答案就没用了。

我要做的是在主数组上有一个函数,它传递一个对象,并检查它的伙伴是否在数组中。如果是,则返回所述对象,否则返回nil。这样,如果需要,您已经拥有了要执行合并的对象。

另外,我并不完全确定你的措辞,但似乎你担心并发成为一个问题(竞争条件,覆盖等)?如果是这种情况,这是一个使用互斥锁的地方的完美示例(如果js还没有使用互斥锁,你可以很容易地创建自己的互斥锁)。只需将我上面提到的功能锁定在开头并在结束时解锁,您就可以避免读取过时的数据。希望有所帮助。

答案 2 :(得分:1)

不是100%肯定我理解问题的细节,但它可能有助于知道javascript是单线程的,所以你永远不必担心真正的并发。你的回调总是一次发生一次。

因此,您不需要“并发数据结构”。很可能任何数据结构都可以工作,因为javascript中没有并发性。 : - )

答案 3 :(得分:0)

如前面的答案中所解释的那样,javascript在限制在主窗口时是单线程的;即使函数被异步调用,它的执行也将是“原子的”(不会中断)。因此,你不能有竞争条件。

然而,处理问题“我不能这样做,因为没有真正的方法来检查回调是否已完成”,请尝试提供等待/通知(全部)机制的http://www.megiddo.ch/jcon-q-rency。我用它来做你的操作。

有了它,您可以延迟执行某个功能,直到满足某个条件。那是你的“//////等待”。当getAllA()和getAllB()完成后,他们可以通知一个负责执行for(b in privates){..}循环的等待函数。