我有一个在循环中运行的异步函数。此函数正在创建一些带日期的HTML按钮。日期应按顺序进行。但最后日期的顺序非常随机。这是我的代码
var getDatesAvailable = function() {
var weekDays = masterConfigurations[0].DaysOfWeek.results;
var advancedDays = masterConfigurations[0].DaysToShow;
var todaysDate = new Date();
var futureDate = new Date(todaysDate);
futureDate.setDate(todaysDate.getDate() + advancedDays);
var availableDates = returnFinalDates(todaysDate, futureDate, weekDays);
var formattedDates = [];
$(availableDates).each(function(i, e) {
var tDate = commonOperations.pad(e.getDate(), 2);
var tMonth = commonOperations.pad((e.getMonth() + 1), 2);
var isoDate = e.getFullYear() + "-" + tMonth + "-" + tDate + "T00:00:00.000z";
formattedDates.push({
"displayDate": (tDate + "/" + tMonth),
"dateObj": isoDate
});
});
var dateButtons = "";
var buttonDates = [];
var schoolCode = $('#selectedSchoolAddress').data('schoolCode') || "";
$(formattedDates).each(function(i, e) {
var startDate = new Date(e.dateObj).toISOString();
var endDate = e.dateObj.split("T")[0];
endDate = (new Date(endDate + "T23:59:59.000z")).toISOString();
commonOperations.queryList("ITFS_Transact_School_Visits", "?$filter=((ITFSVisitDate gt '" + startDate + "') and (ITFSVisitDate lt '" + endDate + "') and (ITFSVisitSchoolCode eq '" + schoolCode + "'))", false).then(function(bookings) {
var maxBookings = masterConfigurations[0].MaxBookingsPerSession;
var bookingsAlreadyHad = bookings.d.results.length || 0;
if (bookingsAlreadyHad >= maxBookings) {
dateButtons = dateButtons + '<button type="button" class="btn btn-default dateButton add10Margin" data-date="' + e.dateObj + '" disabled="disabled">' + formattedDates[i].displayDate + '</button>'
} else {
dateButtons = dateButtons + '<button type="button" class="btn btn-default dateButton add10Margin" data-date="' + e.dateObj + '">' + formattedDates[i].displayDate + '</button>'
}
$("#displayDates").html(dateButtons);
});
});
};
我尝试过很多方法。即使我通过传递false
作为参数来指定不通过异步执行的ajax调用。但仍然没有工作。怎么控制这个?或者有没有什么可以实现使用闭包或任何东西?
我记录了循环的索引它也没有顺序随机出现。
答案 0 :(得分:0)
我可能尝试的一件事是,不是将按钮列表html构建为字符串,而是创建[i
,html]对的数组或{i
:html}映射的对象,以及然后在做.html()
时对它们进行排序并连接。它至少会将同步性作为变量去除。
修改强>
概念证明:http://jsfiddle.net/mkb0fyco/
function randomDeferred(){
var deferred = $.Deferred();
var promise = deferred.promise();
window.setTimeout(function(){
deferred.resolve();
}, Math.random() * 3000 + 1000);
return promise;
}
var dates = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
var buttons = [];
$(dates).each(function(i,e){
$.when(randomDeferred()).then(function(){
buttons[i] = e;
$('body').empty();
$(buttons).each(function(i,e){
if(e) // has it been set?
{
$('body').append('<button>' + e + '</button>');
}
});
});
});
答案 1 :(得分:0)
无法保证commonOperations.queryList()
返回的承诺将以与呼叫相同的顺序结算。
有多种方法可以确保按钮的添加顺序与原始数据相同。这是两个......
<强> 1。等待所有承诺结算,然后渲染按钮
var getDatesAvailable = function() {
var weekDays = masterConfigurations[0].DaysOfWeek.results;
var advancedDays = masterConfigurations[0].DaysToShow;
var todaysDate = new Date();
var futureDate = new Date(todaysDate);
futureDate.setDate(todaysDate.getDate() + advancedDays);
var schoolCode = $('#selectedSchoolAddress').data('schoolCode') || "";
// Here the array returned by `returnFinalDates()` is mapped to an array of promises.
// Each promise will deliver a jQuery-wrapped <button>.
var promises = returnFinalDates(todaysDate, futureDate, weekDays).map(function(i, e) {
var tDate = commonOperations.pad(e.getDate(), 2);
var tMonth = commonOperations.pad((e.getMonth() + 1), 2);
var isoDate = e.getFullYear() + "-" + tMonth + "-" + tDate + "T00:00:00.000z";
var dates = {
"displayDate": (tDate + "/" + tMonth),
"dateObj": isoDate
};
var startDate = new Date(dates.dateObj).toISOString();
var endDate = dates.dateObj.split("T")[0];
endDate = (new Date(endDate + "T23:59:59.000z")).toISOString();
// Return a promise into the `promises` array.
return commonOperations.queryList("ITFS_Transact_School_Visits", "?$filter=((ITFSVisitDate gt '" + startDate + "') and (ITFSVisitDate lt '" + endDate + "') and (ITFSVisitSchoolCode eq '" + schoolCode + "'))", false)
.then(function(bookings) {
// The jQuery-wrapped button returned here becomes the value delivered by the promise pushed into the `promises` array.
return $('<button type="button" class="btn btn-default dateButton add10Margin" data-date="' + dates.dateObj + '">' + dates.displayDate + '</button>')
.prop('disabled', (bookings.d.results.length || 0) >= masterConfigurations[0].MaxBookingsPerSession);
});
});
// When all the commonOperations.queryList() promises are fulfilled,
// loop through the delivered values (buttons) and append them, in order, to #displayDates.
return $.when.apply(null, promises).then(function() {
$("#displayDates").empty();
$.each(arguments, function(i, $button) {
$("#displayDates").append($button);
});
});
};
<强> 2。每个按钮同步附加一个容器,然后将每个按钮异步附加到其容器
由function(i, e) {...}
形成的闭包确保每个按钮与在.map()
循环的同一回合中为其创建的信号匹配。
var getDatesAvailable = function() {
var weekDays = masterConfigurations[0].DaysOfWeek.results;
var advancedDays = masterConfigurations[0].DaysToShow;
var todaysDate = new Date();
var futureDate = new Date(todaysDate);
futureDate.setDate(todaysDate.getDate() + advancedDays);
var schoolCode = $('#selectedSchoolAddress').data('schoolCode') || "";
var promises = returnFinalDates(todaysDate, futureDate, weekDays).map(function(i, e) {
var tDate = commonOperations.pad(e.getDate(), 2);
var tMonth = commonOperations.pad((e.getMonth() + 1), 2);
var isoDate = e.getFullYear() + "-" + tMonth + "-" + tDate + "T00:00:00.000z";
var dates = {
"displayDate": (tDate + "/" + tMonth),
"dateObj": isoDate
};
var startDate = new Date(dates.dateObj).toISOString();
var endDate = dates.dateObj.split("T")[0];
endDate = (new Date(endDate + "T23:59:59.000z")).toISOString();
var $container = $("<span/>").appendTo("#displayDates"); // A span element that is synchronously appended to the #displayDates container.
// Now return a promise into the `promises` array.
return commonOperations.queryList("ITFS_Transact_School_Visits", "?$filter=((ITFSVisitDate gt '" + startDate + "') and (ITFSVisitDate lt '" + endDate + "') and (ITFSVisitSchoolCode eq '" + schoolCode + "'))", false)
.then(function(bookings) {
$('<button type="button" class="btn btn-default dateButton add10Margin" data-date="' + dates.dateObj + '">' + dates.displayDate + '</button>')
.prop('disabled', (bookings.d.results.length || 0) >= masterConfigurations[0].MaxBookingsPerSession)
.appendTo($container);
// As there's nothing more to do below, there's no point returning a value here.
});
});
// When all the commonOperations.queryList() promises are fulfilled, there's nothing more to do
// except return an aggregated promise signifying successful completion (or a failure).
return $.when.apply(null, promises);
};
这两种方法之间的差异主要围绕异步错误的后果。
将附加所有按钮或无 - 任何单一故障都会破坏整个企业。如果一切都成功,所有按钮将在最终承诺解决后一起显示。
即使一个或多个按钮失败,也会附加成功创建的每个按钮。按钮将一次出现一个,因为个人承诺解决。
更进一步,在这两种情况下,你可以插入虚拟按钮(或其他东西)来代替任何失败,尽管代码会稍微复杂一些。