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

How do I deal with two callbacks accessing a datastructure in javascript?

本文关键字:数据结构 回调 两个 访问 javascript 何处理 处理      更新时间:2023-09-26

更新 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 中做到这一点。

怎样才能创建该并发阵列,或者找到一种以其他方式实现我的目标的方法?

<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>

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

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

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

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

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

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

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

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