I need to perform a huge calculation. So, I refer here to create a simple loading screen. Unfortunately, the loading screen is shown after the calculation complete.
Here is my code
class RosterScheduler
{
.........................
autoAssign()
{
var startDate=parseInt($("#autoPlannStartDate").val());
var endDate=parseInt($("#autoPlanEndDate").val());
$("body").addClass("loading");
if (startDate>endDate)
alert("Invalid start date or end date selection");
else
{
if (this.rosterTable.haveInvalidPreferredShift(startDate,endDate))
alert("Invalid shift requirement detected");
else
{
var self=this;
var finalRoster;
var roster,tempAverageSD,lowestAverageSD=100.0;
this.theLowestSDRosters=[];
this.theLowestMissingShiftRosters=[];
for (var i=0;i<100;i++)
{
this._genRoster(startDate,endDate);
}
console.log("Done");
}
}
}
}
I found that if I remark the for loop, the loading screen working properly. If I uncomment the for loop, the loading screen is shown after the "Done" is shown in the console. How can I fix the problem? I have tried to convert the function _genRoster into a Promise function, however, it does not work.
It looks like _genRoster
is blocking the browser, and not giving it any resources to re-render/repaint until the loop is completed. One possibility would be to run the loop after giving the browser a few ms to render the .loading
:
this.theLowestSDRosters = [];
this.theLowestMissingShiftRosters = [];
setTimeout(() => {
for (var i = 0; i < 100; i++) {
this._genRoster(startDate, endDate);
}
console.log("Done");
}, 50);
It might be more elegant to call a function with 0 timeout after a single requestAnimationFrame
, thus giving the browser time to repaint and then running the heavy loop immediately afterwards:
(warning: the following code will block your browser for a bit)
document.body.style.backgroundColor = 'green';
window.requestAnimationFrame(() => {
console.log('start, setting timeout');
setTimeout(() => {
for (let i = 0; i < 1000000000; i++) {
}
console.log('done');
});
});