I’m trying to show a loading indicator when executing a long-running task. The loader should remain visible for the entire duration of the task and then be hidden when the task completes. However, the loader--show class is briefly applied and does not stay visible at all during the execution of the task.
Here’s a simplified version of my code: https://jsfiddle.net/p6ejkdcb/
<button id="test">
Do Something
</button>
<div id="loader" class="loader">
Loading...
</div>
const button = document.getElementById("test");
const loader = document.getElementById("loader");
test.addEventListener("click", (_) => {
new Promise(function (resolve, reject) {
console.log("showLoader");
showLoader();
resolve();
})
.then(function (result) {
for (let i = 0; i < 500000; i++) {
console.log("do the work");
}
return result;
})
.then(function (result) {
console.log("hide the loader");
hideLoader();
return result;
})
})
function showLoader() {
loader.classList.add("loader--show");
}
function hideLoader() {
loader.classList.remove("loader--show");
}
.loader {
display: none;
&--show {
display: block;
}
}
Expected behaviour:
- The loader should become visible when I click the "Do Something" button.
- It should remain visible while the code inside the promise's then() method executes.
- Once the task is complete, the loader should be hidden.
Actual behaviour:
- The loader briefly received the loader--show class but does not stay visible during the execution of the loop.
setTimeout(),fetch(), etc.). Yourforloop is synchronous and blocking, not asynchronous, so your Promise won't do much here.forloop is going to execute all 1000 iterations on the order of a few milliseconds? Computers are fast. You aren't going to be able to visibly see that very much even if your code is working as intended.forloop as a simplification to show that something is happening at that point. In reality it's some pretty weighty DOM interactions (hence why a Worker isn't an option as well) - not ideal but it is what it is. @NickParsons thanks for the link, it looks like the answers there generally use an arbitrarysetTimeoutto change "when" the code runs. Funnily enough that was what I initially doing but it felt like there must be a better way.