1

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

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

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

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

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


更新 1: 现在有代码,还有更多文字!

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

字:

我有一个名为混合的数组。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

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 值,对吧?无论如何,如果他们不这样做,这个答案是没有用的。

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

此外,我不确定您的措辞如何,但您似乎担心并发会成为问题(竞争条件、覆盖等)?如果是这种情况,这是使用互斥锁的完美示例(如果 js 还没有它们,您可以很容易地制作自己的)。只要把我上面提到的功能锁在开头,然后解锁,就可以避免读取过时的数据。希望有帮助。

于 2012-08-08T23:41:27.453 回答
1

不是 100% 确定我理解问题的细节,但知道 javascript 是单线程的可能会有所帮助,因此您永远不必担心真正的并发性。您的回调将始终一次发生一个。

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

于 2012-08-09T00:40:57.597 回答
0

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

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

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

于 2012-08-31T13:43:58.023 回答