我的情况如下:
我需要保存一个包含学生数据的数组。 每个学生都有两个嵌套的分数1年级和2年级分数。
我的目标是为每个学生异常保存数据 - 但在我完成此过程并显示添加的学生数量之前,我需要为每个学生保存第1年和第2年分数的数据。此数据也是异步保存的。
我目前遇到的问题是学生记录被保存,而分数1年级和分数2年级仍在处理中。 Scores Year 1和Scores 2的数据必须异步保存,因为它们之间没有依赖关系。但是,当我准备好显示添加的学生数量时,应保存所有数据。 我还必须说,分数1年级和2年级分数据取决于新的学生ID。
如何使用jQuery promises实现这一目标?如果您运行下面的jsFiddle,您将看到输入的记录数显示在显示分数年数据之前,而它应该是相反的方式。输入的学生总数的显示应取决于分数年份任务的完成情况。另外,我对同步保存学生记录不感兴趣。
以下是代码:(在jsFiddle here中运行代码)
function performUpdate() {
var arr_promises = [];
var students = [
{
id: 1, name: 'John', scoresYear1: [{ subject: 'maths', score: 8 },
{ subject: 'chemistry', score: 7 }], scoresYear2: [{ subject: 'maths', score: 9 }, { subject: 'chemistry', score: 8 }]
},
{
id: 2, name: 'Mary', scoresYear1: [{ subject: 'maths', score: 9 },
{ subject: 'chemistry', score: 8 }], scoresYear2: [{ subject: 'maths', score: 10 }, { subject: 'chemistry', score: 7 }]
}
];
$.each(students, function (index, student) {
arr_promises.push(SaveStudent(student));
});
$.when.apply($, arr_promises).done(function () {
var msg = '<p>Total number of students added: ' + arguments.length + '</p>';
$("div").append(msg);
});
};
function SaveStudent(student) {
var dfrd = $.Deferred();
executeQueryAsync(student,
function () {
var arrScoreYears = [];
// Save scores year 1
$.each(student.scoresYear1, function (index, score) {
executeQueryAsync(score,
function () {
arrScoreYears.push({ status: true });
},
function (sender, args) {
alert('Request failed.');
});
});
// Save scores year 2
$.each(student.scoresYear2, function (index, score) {
executeQueryAsync(score,
function () {
arrScoreYears.push({ status: true });
},
function (sender, args) {
alert('Request failed.');
});
});
$.when.apply($, arrScoreYears).done(function () {
//console.log('added score year 1 - Subject:' + score.subject + ' for student: ' + student.name);
var msg = '<p>Added Score Years for student: ' + student.name + '</p>';
$("div").append(msg);
}).then(function () {
dfrd.resolve({ status: true });
});;
},
// fail
function (sender, args) {
alert('Request failed.');
});
} // end of SaveStudent
function executeQueryAsync(student, callbackSuccess, callbackFail) {
//simulate server call
setTimeout(function () {
callbackSuccess({ status: true });
}, 3000)
}
答案 0 :(得分:1)
如果您想使用$.when
,则必须将一个或多个延迟对象传递给它 - 至少如果您希望 时有任何意义。如果您没有将任何延迟对象传递给$.when
,那么它将立即执行。由于SaveStudent
没有返回值,因此您将一个空数组提供给$.when
- 因此您的“添加的学生总数:...”消息几乎会立即附加。
(如果你不相信我,请看这个小提琴:http://jsfiddle.net/76484/rtdk8ono/)
所以SaveStudent需要返回一个延迟对象:
function SaveStudent(student) {
var dfrd = $.Deferred();
/* other SaveStudent stuff */
return dfrd;
}
完成后,您发现此更改“没有区别”。这是正确的 - 差不多。这是因为dfrd
几乎立即得到解决,基本上与上面解释的原因相同。 dfrd
中的所有延迟对象都已解析后arrScoreYears
得到解决,但arrScoreYears
中没有延迟对象 - 因此dfrd
会立即得到解决。
因此,我们将延迟添加到arrScoreYears
。为了DRYness的利益,我将创建一个单独的功能来完成这个,这样我们就不会重写相同的代码来保存第1年的分数和第2年的分数:
var saveYearScores = function (year_scores, deferreds) {
$.each(year_scores, function (index, score) {
var deferred = $.Deferred();
deferreds.push(deferred);
executeQueryAsync(score,
function () {
deferred.resolve();
},
function (sender, args) {
deferred.fail();
alert('Request failed.');
});
});
};
请注意,我们为异步保存的每年得分创建了延期。我已经选择将包含deferreds的数组传递给函数,以便它可以将新的延迟对象附加到数组中。重要的是,对于SaveStudent
的每次调用,我们都有一个延迟对象数组,每个对象代表一个异步存储分数调用。
现在,我们可以通过调用新函数来替换SaveStudent
中的每个调用:
saveYearScores(student.scoresYear1, arrScoreYears);
saveYearScores(student.scoresYear2, arrScoreYears);
现在$.when
电话实际上等待我们的存款分数调用完成!
我更新了你的小提琴: http://jsfiddle.net/76484/w1pd0cns/4/