#javascript #dom
Вопрос:
Мой проект включает функцию, выполнение которой на более слабых устройствах может занять заметное время, поэтому я хотел бы отобразить значок загрузки для пользователя, пока это происходит. Указанная функция выполняет связку строк, а затем одну запись в DOM.
Мой код выглядит примерно так:
function onclick() {
showLoader();
longDOMWriteCall();
hideLoader();
}
function showLoader() {
loader.classList.remove("hidden");
}
function hideLoader() {
loader.classList.add("hidden");
}
Создается впечатление, что по какой-то причине браузер show
hide
одновременно запускает вызовы и, а также вызов функции записи, в результате чего загрузчик никогда не появляется в первую очередь, несмотря на синхронность кода. Даже выполнение операции асинхронным с использованием обещаний дает тот же результат:
function onclick() {
showLoader();
longDOMWriteCall().then(hideLoader);
}
Как я могу предотвратить это, чтобы загрузчик появился, функция сделала свое дело, а затем загрузчик снова исчез? Этот эффект незаметен на устройстве высокого класса, но на устройстве низкого класса, с которым я тестировал, может потребоваться до половины секунды для завершения вызова.
Ответ №1:
Запустите код асинхронно с setTimeout()
помощью .
В приведенном ниже примере у меня большой тайм-аут, поэтому эффект виден на обычных компьютерах. Вы можете использовать 0
на реальном устройстве.
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>
Комментарии:
1. Спасибо! Именно то, что мне было нужно!
Ответ №2:
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>
Вы можете попробовать тайм-аут остроумия:
showLoader();
setTimeout(()=> {
longDOMWriteCallAsync()
hideLoader()
},1)