Reputation: 18619
I'm creating a progam, where JavaScript is processing a huge amount of data, so I want to show the progress on a progressbar.
The problem comes here: While the for loop is running, the progressbar does not update, and then it will be fullfilled immediately.
document.getElementById("start").addEventListener("click",function(){
max=1000000
document.getElementById("pb").max=max
for(i=0;i<max;i++){
document.getElementById("pb").value=i+1
}
console.log("Finished")
})
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>
How can I solve that problem?
I don't want to use any JS library, if it's possible without them.
Thanks for any help!
Upvotes: 2
Views: 602
Reputation: 24191
Here is a way of doing this async / await
way,.. So you can keep your for loop.
Also notices I've reduced the max to 1000, as waiting 4 and half hours might be overkill. :)
function sleep(ms) { return new Promise((r) =>
setTimeout(r, ms)); }
async function run() {
let max=1000;
document.getElementById("pb").max=max;
for(let i=0;i<max;i++){
document.getElementById("pb").value=i+1
await sleep(0);
}
console.log("Finished")
}
document.getElementById("start").
addEventListener("click", run);
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>
Update, the above snippet was deliberately not optimized to keep things simple. But one issue with the above the
sleep(0)
is called way more often than required, as such I've created a slightly more complex example that processes some CPU intensive task, and how to handle this.
function sleep(ms) { return new Promise((r) =>
setTimeout(r, ms)); }
function doSomeWork() {
//wait about 5ms
const st = Date.now();
while (Date.now() - st < 5);
}
async function run() {
let max = 1000;
let lTm = Date.now();
const pb = document.getElementById("pb");
document.getElementById("pb").max=max;
for(let i=0;i<max;i++){
doSomeWork();
const tm = Date.now();
if (tm - lTm > 100 || i === max -1) {
pb.value=i+1;
await sleep(0);
}
}
console.log("Finished")
}
document.getElementById("start").
addEventListener("click", run);
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>
Upvotes: 1
Reputation: 12161
You can use requestAnimationFrame
:
document.getElementById("start").addEventListener("click",function(){
var max=100;
var p=0;
document.getElementById("pb").max=max;
var update = function () {
document.getElementById("pb").value=p;
p++;
if (p <= max) requestAnimationFrame(update);
else console.log("Finished");
};
update();
})
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>
Or just use setTimeout
and increase the timer:
document.getElementById("start").addEventListener("click",function(){
max=100;
document.getElementById("pb").max=max;
for(i=0;i<max;i++){
setTimeout(function () {
document.getElementById("pb").value=this;
if (this == max) console.log("Finished")
}.bind(i+1), i*16);
}
})
<progress id="pb" value="0" max="0"></progress>
<input type="button" id="start" value="Start"/>
Upvotes: 2