skip to Main Content

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.

3

Answers


  1. You should use a promise with setTimeout to mimic your heavy calculations.

    The for will complete instantly

    const button = document.getElementById("test")
    const loader = document.getElementById("loader")
    const showLoaderButton = document.getElementById("showLoader")
    
    showLoaderButton.addEventListener("click", (_) => showLoader())
    
    test.addEventListener("click", (_) => {
        showLoader();
        
        new Promise((resolve, reject) => setTimeout(resolve, 2000))
          .then(hideLoader)
    })
    
    function showLoader() {
      loader.classList.add("loader--show")
    }
    function hideLoader() {
      loader.classList.remove("loader--show")
    }
    .loader {
         display: none;
    }
     .loader--show {
         display: block;
    }
    <button id="test">
    Do Something
    </button>
    
    <button id="showLoader">
    Just show a loader
    </button>
    
    <div id="loader" class="loader">
    Loading...
    </div>
    Login or Signup to reply.
  2. When you add classlist with name
    –loader–show

    But in your css
    You use class name as separate
    Lile –loader{
    &–show
    }

    Use like this
    –loader–show{
    Write css
    }

    Login or Signup to reply.
  3. You just need to hide your loader right after the resolve() call inside the Promise.

    const myLoader = document.querySelector('#loader');
    
    function closeLoader ()
    {
      myLoader.style.display = 'none';
    }
    
    function openLoader ()
    {
      myLoader.style.display = 'block';
    }
    
    function doHeavyWork ()
    {
      // Show the loader.
      openLoader();
      
      return new Promise
      (
        ( resolve, reject ) =>
        {
          // Do your heavy work here.
          console.log('Heavy work started.');
          
          // Simulating some heavy work.
          setTimeout
          (
            () =>
            {
              console.log('Heavy work stopped.');
              
              // Resolve the Promise.
              resolve();
              
              // Hide the loader.
              closeLoader();
            },
            3000 // 3 seconds wait.
          );
        }
      );
    }
    #loader
    {
      display: none;
    }
    <button onclick='doHeavyWork()'>Do Something</button>
    
    <div id='loader'>Loading...</div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search