我有一系列支持一系列级联下拉选择列表的ajax请求。当你在第一个下拉列表中选择一个值时,会触发一个请求来填充第二个,当它完成时(并且下拉填充),下一个请求将触发填充第三个下拉列表,依此类推。
这些请求链的形成方式有一些变化,所以我希望使用jQuery Deferred对象来组合请求。
我知道如何将第二个请求链接到第一个请求,但我不知道如何将第三个请求链接到第二个请求。
function Step1() { return $.ajax(<foo>);}
function Step2() { return $.ajax(<foo>);}
function Step3() { return $.ajax(<foo>);}
$(function() {
Step1().then(Step2).then(Step3);
});
意图是当Step2被解析时触发Step3,但.then(Step2)
返回的延迟对象来自Step1,因此Step3被添加为Step1的回调。
如果你能看到this jsFiddle sample,我认为我想要做的更清楚。 修改:Here是相同的脚本,并在第二次调用中添加了延迟,以使其更加明显。
答案 0 :(得分:3)
$(function() {
$.when(Step1).then(function() {
$.when(Step2).then(Step3);
});
});
对于错误处理,我建议您将Stepn重写为:
function Stepn() {
return $.ajax(<foo>).fail(function() {
// handle failure
});
}
使用此格式的回调可以让您按照自己的意愿行事。如果你有超过5个步骤,缩进变得一团糟,为此构建队列可能是值得的。
这是一个实时example
var Queue = function() {
var q = [];
var that = this;
// If items in queue then run them.
function moveNext() {
if (q.length > 0) {
that.runItem();
}
}
// run first item in queue
this.runItem = function() {
// get item
var item = q.shift();
// when deferred object then run then ...
$.when(item.item).then([item.options.done, function() {
// item finished, move to next.
moveNext();
}], [item.options.fail, function() {
// if run item always then move next on failure.
if (item.options.always) {
moveNext();
}
}]);
};
this.add = function(def, options) {
// if array then call add on each item in array
if ($.isArray(def)) {
for (var d in def) {
this.add(d, options);
}
// return as we are done.
return this;
}
// push item onto array
q.push({
item: def,
options: options
});
// if items & not delay then run item.
if (q.length === 1 && !options.delay) {
this.runItem();
}
// enable jQuery style chaining \o/
return this;
};
};
Queue.add([def, def, ...], options)
将一个defferred项或一组延迟项添加到队列中。可以与单个延迟项或数组一起使用。选项图如下
{
"delay" : Boolean, // if true do not run the item in the queue after appending it.
"done" : Function, // optional done call back
"fail" : Function, // optional fail call back
"always": Boolean // if true run the next item in the queue even if this item fails.
}
Queue.runItem
,一个运行队列中下一个项目的函数。在内部调用,可以手动与延迟属性串联使用。
答案 1 :(得分:0)
我最近开始挣扎于此(请参阅我的问题here),灵感来自James Coglan的blog series。
在对'monads'进行了一段时间的讨论后,我回过头来希望可以将延迟的对象“链接”在一起。问题是“done”返回相同的延迟对象,而不是新对象。
我浏览了一段时间的jquery代码,并认为我无法在Deferred或_Deferred代码中注入任何内容。但是, 可以将我们自己的对象作为参数注入promise()
函数。因此,如果我们创建一个能为我们带来可链接承诺的函数......
var Chainable = function Chainable() {
return {
chain : function(next) { //next: another function which returns Deferred
var newDef = $.Deferred(); //we resolve this when next is done
//next line: call next with (a||null) for method-tolerance
this.done(function(a) { next(a||null).done(newDef.resolve); });
return newDef.promise(Chainable());
}
};
}
...我们可以用它来改变我们的风格:
var asyncMessage = function(msg) {
var dfd = new jQuery.Deferred();
setTimeout(function() { dfd.resolve(msg); }, 1000);
return dfd.promise(Chainable());
};
asyncMessage("Chained:A")
.chain(function(m) { return asyncMessage(m + "B"); })
.chain(function(m) { return asyncMessage(m + "C"); })
.done(log); // -> outputs "ABC"
请参阅此处的jsfiddle以了解'之前/之后'代码示例:http://jsfiddle.net/Benjol/DjrRD/
答案 2 :(得分:0)
我们很幸运,在时间表上有一些灵活性。我们最终使用jQuery 1.6中添加到延迟对象的.pipe()
链接。
感谢大家的帮助!