顺序的、依赖的延迟调用
Sequential, Dependent Deferred calls
我有两个函数getStudentById(studententid)和getBookTitleById(bookId)其中数据是通过ajax调用检索的(这些函数是单独的)
我的目标,使用deferred:
- 获取学生对象,
- 然后根据Student对象的favoriteBookId属性获取书名,
- 然后调用方法showMessage(student, bookTitle)导致"John likes Book 222"
这个例子是简化的。本质上,目标是连续进行一定数量的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(学生,bookTitle),其中参数是每个ajax调用链的结果
我找不到一个(优雅的)示例,其中顺序延迟调用的所有结果都可以在链的末尾访问,因为如果done函数获得LAST 的结果,那么
我最好的解决方案是将第二个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);
});
Genob,你的"最佳解决方案"是完全可行和可接受的。它只需要整理:
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);
});
这种方法(两种变体)可以概括为"在一个累加器对象中沿着承诺链传递数据",或者更简单地说是"承诺数据累加器"模式(我的术语——你在其他任何地方都找不到)。
无论如何实现,保持"消费者"方法(终端.done()
)不受嵌套/闭包的限制是好的。
将承诺链接在一起的另一种方法是让一个then
处理程序返回另一个承诺。这样做的好处是,你可以利用闭包在第二个承诺的解析中引用第一个承诺解析中的变量。
所以你的例子看起来像:
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
已经返回了一个承诺,你不需要把它包装在一个deferred中,然后从它那里获得承诺。你已经使用闭包将这两个属性包装成一个对象;没有理由(至少我没有看到)你需要把这些属性包装起来,然后在另一个地方对它们做一些事情,而不是在那里对它们做一些事情。
- jQuery延迟了ajax调用的循环
- 使用jquery延迟对象链接多个ajax调用
- jQuery通过嵌套的ajax调用延迟对象
- jQuery 延迟的 AJAX 调用返回值
- 如何在 JS 中调用 2 次或更多次时延迟函数执行
- AJAX 调用和表单提交之间的延迟
- 如何按顺序调用延迟函数
- 使用promise或setTimeout确定延迟函数的调用顺序
- 如何调用具有延迟的函数
- 将for循环从完成延迟到返回API调用
- 在JS文件中设置延迟以调用JS文件
- jQuery deferred:用于延迟函数的返回,直到函数内的异步调用完成+获取返回值
- 防止 JavaScript 调用延迟出现
- Javascript AJAX函数调用延迟
- 将第一个函数调用延迟n秒
- jsTree v.3使用ajax调用延迟加载
- 导致ajax调用延迟的原因是什么?
- 函数调用延迟
- 如果在此期间发生其他事件,如何停止调用延迟函数
- Internet Explorer启动AJAX调用延迟