我认为我需要使用“then”处理程序创建一个Deferred对象,但是等到“then”处理程序完成它自己的承诺后再继续。
用例是一个记录对象,上面的函数是它的保存方法。记录对象有一个名为saveQueue的属性,在记录的实例化中设置为$ .Deferred()。对saveQueue的解析调用应该确保Deferred总是会尽可能快地执行附加到它的每个新处理程序。这个想法是你可以在短时间内在记录上多次调用save,但调用会一个接一个地运行,而不是重叠。
我正在使用Deferred来排队Ajax调用,因此在前一次调用完成之前不会运行。但是,从同一个方法,我想返回一个可以被jQuery Ajax对象解析/拒绝的Deferred,如下所示:
record.saveQueue = $.Deferred();
self.save = function( record ){
var deferredAction = $.Deferred();
deferredAction.then(function() {
return $.post("/example_save_endpoint");
});
record.saveQueue.always(function(){
deferredAction.resolve();
}).resolve();
return deferredAction;
}
然而,当我使用这段代码时,deferredAction
承诺总是以resolved
结束,大概是因为#then处理程序返回一个“挂起”(因而是非拒绝)的承诺。在解决/拒绝之前,有没有办法强制Deferred等待Ajax承诺完成?或者是否有另一种更好的方法来穿针呢?
答案 0 :(得分:0)
我可能会选择不这样做,但延迟/承诺确实可以用作排队设备。
你需要对你已经尝试的内容进行轻微的(?)变异。
self.queue = $.when();//A resolved promise, used to form a queue of functions in a .then() chain.
self.save = function(data) {
var dfrd = $.Deferred();//A Deferred dedicated to this particular save.
self.queue = self.queue.then(function() {
return $.post("/example_save_endpoint", data) //Make the AJAX call, and return a jqXHR to ensure the downstream queue waits for this jqXHR to resolve/reject.
.then(dfrd.resolve, dfrd.reject) //Resolve/reject the Deferred for the caller's benefit
.then(null, function() {
//Force failure down the success path to ensure the queue is not killed by an AJAX failure.
return $.when();//Return a resolved promsie, for the queue's benefit.
});
});
return dfrd.promise();//allow the caller to do something when the AJAX eventually responds
}
有关说明,请参阅代码中的注释
答案 1 :(得分:0)
您的想法可能有效,但
.resolve()
解析队列,而应仅使用已解决的promise初始化该队列。record.saveQueue
上实际队列,需要在每次方法调用时更改(覆盖),以表示最新请求的结束。我们don't need any deferreds为we can work with the promises,$.post
返回。
所以使用这个:
var emptyQueue = $.when(undefined); // an already fulfilled promise as the start
// equivalent: = $.Deferred().resolve().promise();
function startQueue() {
return emptyQueue; // yes, this delibaretely returns a constant, the begin
// of the queue always looks the same (and is never mutated)
}
// every time you create a record, do
record.saveQueue = startQueue();
// and use that in your methods:
this.save = function(record) {
var queuedRequestResult = record.saveQueue.then(function() {
return $.post("/example_save_endpoint");
// ^^^^^^ promises chain :-)
});
// Magic happens here:
record.saveQueue = queuedRequestResult // we swap the previous queue promise for a new
// one that resolves only after the request
.then(startQueue, startQueue); // and make sure it then starts with a fresh
// queue, especially when the request failed
//.then(null, startQueue) is similar, except unnecessarily remembering the last result
return queuedRequestResult;
}