Mi proyecto incluye una función que puede tardar bastante en completarse en dispositivos más débiles, por lo que me gustaría mostrar un icono de carga al usuario mientras esto sucede. Dicha función realiza un montón de concatenación de cadenas y luego una sola escritura en el DOM.
Mi código se parece a esto:
function onclick() { showLoader(); longDOMWriteCall(); hideLoader(); } function showLoader() { loader.classList.remove("hidden"); } function hideLoader() { loader.classList.add("hidden"); } Parece como si, por alguna razón, el navegador ejecutara las llamadas show y hide , así como la llamada escribir desde la función, al mismo tiempo, lo que hace que el cargador nunca aparezca en primer lugar, a pesar de que el código es síncrono. Incluso hacer que la operación sea asíncrona usando promesas produce el mismo resultado:
function onclick() { showLoader(); longDOMWriteCall().then(hideLoader); }¿Cómo puedo evitar que esto suceda, de modo que aparezca el cargador, la función haga lo suyo y luego el cargador desaparezca nuevamente? El efecto es imperceptible en un dispositivo de gama alta, pero el dispositivo de gama baja con el que probé puede tardar hasta medio segundo en completar la llamada.
Ejecute el código de forma asíncrona con setTimeout() .
En el siguiente ejemplo, tengo un tiempo de espera prolongado, por lo que el efecto es visible en las computadoras normales. Puede usar 0 en el dispositivo real.
const loader = document.getElementById("loader"); const container = document.getElementById("container"); function clickFuncAsync() { showLoader(); longDOMWriteCallAsync().then(hideLoader); } function longDOMWriteCallAsync() { console.log("Running async"); return new Promise(resolve => { setTimeout(() => { let html = ""; for (let i = 0; i < 5; i++) { html += "<div>Content</div>"; } container.innerHTML = html; resolve(); }, 1000); }); } function showLoader() { loader.classList.remove("hidden"); } function hideLoader() { loader.classList.add("hidden"); } #loader { height: 32px; width: 32px; } #loader.hidden { display: none; } <button onclick="clickFuncAsync()"> Run Async </button> <div id="loader" class="hidden"> <img src="https://picsum.photos/32/32"> </div> <div id="container"> </div> const loader = document.getElementById("loader"); const container = document.getElementById("container"); function clickFunc() { showLoader(); setTimeout(()=> { longDOMWriteCall(); hideLoader(); }, 1) } function clickFuncAsync() { showLoader(); setTimeout(()=> { longDOMWriteCallAsync() hideLoader() }, 1) } function longDOMWriteCall() { console.log("Running sync"); let html = ""; for (let i = 0; i < 50000; i++) { html += "<div>Content</div>"; } container.innerHTML = html; } function longDOMWriteCallAsync() { console.log("Running async"); return new Promise(resolve => { let html = ""; for (let i = 0; i < 50000; i++) { html += "<div>Content</div>"; } container.innerHTML = html; resolve(); }); } function showLoader() { loader.classList.remove("hidden"); console.log('sdfds') } function hideLoader() { console.log('vvvvv') loader.classList.add("hidden"); } #loader { height: 32px; width: 32px; } #loader.hidden { display: none; } <button onclick="clickFunc()"> Run </button> <button onclick="clickFuncAsync()"> Run Async </button> <div id="loader" class="hidden"> <img src="https://picsum.photos/32/32"> </div> <div id="container"> </div>Puedes probar con el tiempo de espera:
showLoader(); setTimeout(()=> { longDOMWriteCallAsync() hideLoader() },1)