我有两个函数 getStudentById(studentId)和 getBookTitleById(bookId),其中数据通过ajax调用检索(这些函数将保持不变)
我的目标,使用Deferreds:
此示例已简化。本质上,目标是连续进行一定数量的ajax调用,其中下一个调用取决于前一个调用的结果,最后提供对所有结果的访问权限
代码:
var getStudentById = function(studentId){
return $.Deferred(function(def){
def.resolve({name:"John",favoriteBookId:222}); //assume ajax gets Student obj
}).promise();
}
var getBookTitleById = function(bookId){
return $.Deferred(function(def){
def.resolve("Book " + bookId); //assume ajax call gets title
}).promise();
}
var showMessage = function(student, bookTitle){
alert(student.name + " likes " + bookTitle)
}
我见过许多遵循以下模式的解决方案
deferred_a.then(b).then(c).then(y).then(z).done(r)
将转换为:
getStudentById(5) //resolves with student object
.then(function(student){
return getBookTitleById(student.favoriteBookId)}
)
.done(function(bookTitle){
alert(bookTitle); //obviously this works
// how can I get reference to the student object here? so i can say:
// showMessage (student, bookTitle)
});
但我需要调用方法 showMessage(student,bookTitle),其中参数是链中每个ajax调用的结果
我找不到一个(优雅)示例,其中所有顺序延迟调用的结果都可以在链的末尾访问,因为 done 函数获取最后的结果然后
我最好的解决方案是在工厂类型方法中包装第二个Deferred,但这不是最佳解决方案,对吧?我是否遗漏了延期用法中应该简化的内容?
getStudentById(5)
.then(function(student){
return $.Deferred(function(def){
getBookTitleById(student.favoriteBookId)
.done(function(bookTitle){def.resolve({student:student, bookTitle:bookTitle})})
}).promise();
})
.done(function(studentAndBookTitle){
alert(studentAndBookTitle.student.name + " likes " + studentAndBookTitle.bookTitle);
});
答案 0 :(得分:0)
将promises链接在一起的另一种方法是让一个then
处理程序返回另一个promise。这样做的好处是你可以利用闭包来引用第二个promise的解析中第一个promise的解析中的变量。
所以你的例子看起来像:
getStudentById(5)
.then(function(student) {
return getBookTitleById(student.favoriteBookId)
.then(function (bookTitle) {
doSomethingWithStudentAndBookTitle(student, bookTitle)
});
});
function doSomethingWithStudentAndBookTitle(student, bookTitle) {
alert(student.name + " likes " + bookTitle);
}
编辑:此解决方案与您的上一个代码段有些相似;但
getBookTitleById
已经返回一个承诺,您不需要将其包裹在延期中,然后从中获得承诺。
您已经使用闭包将这两个属性包装到一个对象中;没有理由(至少没有我能看到的)你需要将这些属性包起来,然后在不同的地方对它们做些什么,而不是仅仅在那里做些什么。
< / LI> 醇>编辑2:创建了一个将数据消耗与数据提供分开的功能。
答案 1 :(得分:0)
Genob,您的最佳解决方案&#34;是完全可行和可接受的。它只需要整理:
getStudentById(5).then(function(student) {
return getBookTitleById(student.favoriteBookId).then(function(bookTitle) {
return {
student: student,
bookTitle: bookTitle
});
}).done(function(superObj) {
alert(superObj.student.name + " likes " + superObj.bookTitle);
});
您可能也会考虑相同方法的温和变体,这是可能的,因为student
已经是一个对象,允许它被扩展而不是创建一个超级对象。
getStudentById(5).then(function(student) {
return getBookTitleById(student.favoriteBookId).then(function(bookTitle) {
return $.extend(student, {
favoriteBookTitle: bookTitle
});
});
}).done(function(extendedStudent) {
alert(extendedStudent.name + " likes " + extendedStudent.favoriteBookTitle);
});
这种方法(两种变体)可以概括为&#34;在累加器对象中沿着承诺链传递数据&#34;或者更简单地说是承诺的数据累加器&#34;模式(我的术语 - 你不会在其他任何地方找到它。)
无论如何实现,保持&#34;消费者&#34;方法(终端.done()
)不受嵌套/闭包的限制。