我试图基于jquery延迟对象链接一些调用。为简单起见,我想:
起初,我写了类似的东西:
myFirstFunction()
.progress(myFirstProgressCallback)
.done(myFirstDoneCallback)
.then(mySecondFunction)
.progress(mySecondProgressCallback)
.done(mySecondDoneCallback);
但是我发现了一些我没想到的东西(在阅读文档之后,它似乎是它的工作方式):
示例you can run it in this jsbin:
function async(number){
var def = new $.Deferred();
setTimeout(function(){
def.notify("Hello from " + number);
}, 300);
setTimeout(function(){
def.resolve("I'm done " +number);
}, 600);
return def.promise();
}
async(1)
.progress(function(msg){
console.log("First progress: " + msg);
})
.done(function(msg){
console.log("First done: " +msg);
})
.then(function(){
return async(2);
})
.progress(function(msg){
console.log("Second progress: " + msg);
})
.done(function(msg){
console.log("Second done: " +msg);
});
控制台中的结果:
"First progress: Hello from 1"
"Second progress: Hello from 1"
"First done: I'm done 1"
"Second progress: Hello from 2"
"Second done: I'm done 2"
第一反应:"为什么地狱??????"
第二:"我怎样才能做我想做的事?"
我用这个替换了我的代码,效果很好(jsbin):
function async(number){
var def = new $.Deferred();
setTimeout(function(){
def.notify("Hello from " + number);
}, 300);
setTimeout(function(){
def.resolve("I'm done " +number);
}, 600);
return def.promise();
}
async(1)
.progress(function(msg){
console.log("First progress: " + msg);
})
.done(function(msg){
console.log("First done: " +msg);
})
.then(function(){
return async(2)
.progress(function(msg){
console.log("Second progress: " + msg);
})
.done(function(msg){
console.log("Second done: " +msg);
});
});
输出:
"First progress: Hello from 1"
"First done: I'm done 1"
"Second progress: Hello from 2"
"Second done: I'm done 2"
如何避免在"然后"内部的函数内注册进度回调?声明?
答案 0 :(得分:1)
这个想法可能对你有用:检查回调中的上下文。
默认情况下,回调的上下文是触发操作的承诺:
var async2,
async1 = async(1);
async1
.done(function (msg) {
if (this === async1) {
console.log("First done: " + msg);
}
})
.fail(function (msg) {
if (this === async1) {
console.log("First fail: " + msg);
}
})
.progress(function (msg) {
if (this === async1) {
console.log("First progress: " + msg);
}
})
.then(function (msg) {
async2 = async(2);
return async2;
})
.done(function (msg) {
if (this === async2) {
console.log("Second done: " + msg);
}
})
.fail(function (msg) {
if (this === async2) {
console.log("Second fail: " + msg);
}
})
.progress(function (msg) {
if (this === async2) {
console.log("Second progress: " + msg);
}
});
我不确定这是否比在then
内嵌套进度回调更好。一个问题是,可以使用特定上下文执行操作(使用notifyWith
,resolveWith
,rejectWith
)。
比您要求的更多信息
我刚才发现了同样的行为,感受到了同样的挫败感,并且达到了你所做的同样的分辨率。从那以后,我对通知/进展的工作方式做了一些研究,这就是我发现的:
then
会返回一个新的承诺,但它也会将前承诺中的所有操作(resolve
,reject
,notify
)转发给后一个承诺。事实上,只要您向承诺链添加错误处理,您就会发现此行为也会扩展到fail
回调:
function async(number){
var def = new $.Deferred();
setTimeout(function(){
def.notify("Hello from " + number);
}, 300);
setTimeout(function(){
def.reject("I've failed " + number);
}, 450);
return def.promise();
}
async(1)
.progress(function(msg){
console.log("First progress: " + msg);
})
.fail(function(msg){
console.log("First fail: " +msg);
})
.then(function(){
return async(2);
})
.progress(function(msg){
console.log("Second progress: " + msg);
})
.fail(function(msg){
console.log("Second fail: " +msg);
});
输出:
"First progress: Hello from 1"
"Second progress: Hello from 1"
"First fail: I've failed 1"
"Second fail: I've failed 1"
即使永远不会调用第二个async
,也会执行所有progress
和fail
回调。同样的事情虽然很少,但如果你为它提供除函数之外的任何东西,那么就会出现完成处理程序:
async(1)
.progress(function(msg){
console.log("First progress: " + msg);
})
.done(function(msg){
console.log("First done: " +msg);
})
.then('foo')
.progress(function(msg){
console.log("Second progress: " + msg);
})
.done(function(msg){
console.log("Second done: " +msg);
});
输出:
"First progress: Hello from 1"
"Second progress: Hello from 1"
"First done: I'm done 1"
"Second done: I'm done 1"
所以我想我想说的是,你在进程回调中看到的行为与Deferred对象的工作方式并不矛盾。
在我的调查开始时,我乐观地认为我们可以使用Promises/A+样式激发我们想要的行为:promise.then(doneFilter, failFilter, progressFilter)
:
async(1)
.then(function (msg) {
console.log("First done: " + msg);
return async(2);
},
null /*Failure Handler*/,
function (msg) {
console.log("First progress: " + msg);
})
.then(function (msg) {
console.log("Second done: " + msg);
},
null /*Failure Handler*/,
function (msg) {
console.log("Second progress: " + msg);
});
不幸的是,结果并不好:
"First progress: Hello from 1"
"Second progress: undefined"
"First done: I'm done 1"
"Second progress: Hello from 2"
"Second done: I'm done 2"
有趣的是,第二次进度回调的第一次执行没有提供正确的值。我没有进一步调查,除了确认Q(支持进度/通知的承诺的另一个实现)提供相同的结果。
最后,我回答了一个问题,帮助我澄清了为什么这一切都有效:
如果所有操作都转发到下一个承诺,为什么这些转发的操作不会调用嵌套的进度处理程序?
解决了第一个承诺并且下一个异步任务待处理后,progress
处理程序被添加为回调。与done
和fail
不同,progress
处理程序需要在执行相应操作(notify
)时附加。