当我将数据发布到一系列位置时,我正在使用 Firebase 并尝试使用 jQuery Deferred。我想要一种机制,如果任何帖子失败,我想恢复并可能撤消以前的帖子。
进行 Firebase 帖子的语法是
var fbRef = new Firebase("https://my.firebaseIO.com/path/to/data");
fbRef.set(data,function (error){
if (error){
// do something about it
} else {
// all went well
// next post would go here...
}
}
自然地以这种方式写一系列帖子 - 其中每个取决于前一个的成功将导致代码金字塔 AKA 回调地狱。
对于我的具体示例,我有关于需要放在不同位置的“单词”的数据
/words/upCase/<word>/id =<word>
/words/upCase/<word>/type = <type>
/words/<type>/<word>/id = <word>
其中每一个都有自己的 Firebaseset(data,cb)
调用,如果它们的任何先例失败,则不应执行后两个调用。这是一个简化的示例,因此该解决方案应适用于更多数据点。
此外,在此示例中,没有从一个操作到下一个操作的数据流,所有数据一开始都是已知的,因此我也对数据流示例感兴趣。
我最近的尝试涉及泛化回调
// function factory. function will set firebase reference value and handle the deferred if exists
var makeFn=function (fbr,val,task){
return function (){
fbr.set(val,function (err){
if (err) {
console.log(fbr.toString()+' Error in Firebase:'+err.toSource());
if (task) {
task.reject(err);
}
}
if (task) {
task.resolve(fbr);
}
});
if (task) {
return task.promise();
}
}
}
// factory that returns a function that returns a promise about setting data
var make=function (fbr,val){
return function (){
var task=new $.Deferred();
return makeFn(fbr,val,task)();
}
};
然后我这样打电话
var fbr = new Firebase("https://my.firebaseIO.com/words/upCase/" + word + "/id");
make(fbr,word)() // set id promise
.done(makeFn(fbr.parent().child('type'),type)) // HERE, not right
.done(makeFn(fbr.parent().parent().parent().child(type).child(word).child('id'),word)) // set third data, still not right
.done(function(){
//inform all went well
}
);
我的尝试没有按照我的意图链接依赖项。我想说的是……
make(fbr,word).done(<new promise returning fn>).<get the done of that new promise>(...)
...没有像金字塔一样的金字塔:
make(fbr,word).done(
<new promise returning fn>.done(
...
)
)
我可以肯定的一件事是我做错了什么。如何在不堆积我的代码的情况下链接依赖项?对待我,就好像我对承诺不熟悉一样,因为我是。=)
更新
这是我想出的一个演练。这只是处理二传手。
当我们想要设置时,首先扩展Firebase
返回我称之为promisy函数的东西,我只是.s()
在这里使用......
Firebase.prototype.s=function(v){
var fn=makeSet(this,v);
return fn;
};
这是制造商,它有一些共同点......
var makeSet=function (fbr, val){
// factory that returns a function that returns a promise about setting data
var task=Q.defer();
var fn=setFn(fbr,val,task);
makeCOMMON(task,fn,fbr);
return fn;
};
在共同点中,我们将函数和 Promise 联系起来,并且还创建了一种新的类型,.then()
它返回馈入其中的 fn 的 Promise,它被称为.ok()
.
var makeCOMMON=function (task, fn, fbr){
var p=task.promise;
fn.task=task;
fn.fbr=fbr.toString();
fn.p=p;
p.fbr=fbr.toString();
p.fn=fn;
p.ok=function (fnn){
this.then(fnn);
return fnn.p;
};
}
那部分可能是多余的,也许是不确定的,它暴露了我的无知。返回setFn()
:
var setFn=function (fbr, val, task){
// function factory. function will set firebase reference value and handle the deferred if exists
return function (){
task.notify('Setting '+fbr.toString()+' to '+val.toSource());
fbr.set(val,function (err){
if (err) {
task.notify('Rejecting Update due to error '+fbr.toString());
task.reject({
error:err,
FbPath:fbr.toString(),
FbTask:task,
FbVal:val,
toString:function(){
var s='';
s+=' '+this.error.toString();
s+=' '+this.FbPath;
if (this.FbVal) {
s+=' '+this.FbVal.toSource();
}else{
s+=' null';
}
return s;
}
});//reject
}else{
task.resolve(fbr);
}
});
return task.promise;
};
}
紧张气氛越来越大......现在,当我调用它时,我有一个链接机制:
add:function(w,type){
w=w.toLowerCase();
var fn0,fnLast;
var fbr=FirebaseSvc.get();
var proms=[];
//
var chain=function(fbrFn){
var wasFirst=false;
if (typeof fn0=='undefined') {
wasFirst=true;
fn0=fbrFn;
}
proms.push(fbrFn.p);
fbrFn.p.progress(logProgress);
fbrFn.p.fail(logFail);
if (!wasFirst) {
var rv=fnLast.p.ok(fbrFn);
fnLast=fbrFn;
return rv;
}else{
fnLast=fbrFn;
return fbrFn.p;
}
};
//
//.c() is .child() alias
chain(fbr.root().c('words/upCase/'+w+'/id').s(w));//This is returing a promise, so I can still do promisy things, but I am not right now
chain(fbr.root().c('words/upCase/'+w+'/type').s(type));
chain(fbr.root().c('words/words'+type+'/'+w+'/id').s(w));
//
var ro={
promise:Q.all(proms),
doIt:fn0
};
return ro;
},//.add
从客户端,它是:
var ro=WordSvc.add(w,type);
ro.promise...// can attach handlers
ro.doIt();// kick it all off