更新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中这样做。
我如何创建并发数组,或者想办法以其他方式实现我的目标?
答案 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){..}循环的等待函数。