当我将数据发布到一系列位置时,我正在使用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>
其中每个都有自己的Firebase set(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;
};
在共性中,我们链接函数和promises,并创建一种新的.then()
,它返回fn的赋值,它被称为.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;
};
}
紧张感......现在,当我打电话给我时,我有一个chainer机制:
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
答案 0 :(得分:0)
我不确定我是否完全明白,但是这样的事情应该可以胜任。
首先,两个实用功能:
function fbSet(path) {
var dfrd = $.Deferred(),
fbRef = new Firebase("https://my.firebaseIO.com/" + path);
fbRef.set(data, function (error) {
if (error) {
dfrd.reject(fbRef, error);
} else {
dfrd.resolve(fbRef);
}
}
return dfrd.promise();
}
function doFbChain(paths, word, type) {
var dfrd = $.Deferred();
$.each(paths, function(i, path) {
path = path.replace('<word>', word).replace('<type>', type);
dfrd = dfrd.then(fb(path));
});
return dfrd.promise();
}
现在,一些示例应用程序代码:
var myPaths = [
'/words/upCase/<word>/id',
'/words/upCase/<word>/type',
'/words/<type>/<word>/id'
];
var myWord = 'myWord';
var myType = 'myType';
doFbChain(myPaths, myWord, myType).done(function() {
//overall success
}).error(function(fbRef, error) {
//failure somewhere along the way
});
您需要使用代码来使其完全符合您的要求。