TL;博士:
-
loadingSpinner
div 在昂贵的代码之前打开,在昂贵的代码之后关闭 - 两者
showLoading()
和hideLoading()
调用log()
它将一条消息写入console.log()
和一个元素的innerHTML
loadingSpinner
在昂贵的代码完成之前,DOM 中的日志消息不会显示,但console.log()
消息在应该出现的时候出现
我有一个对存储在 loadingSpinner
中的 div 的引用这只是一个位于所有其他内容之上的框,应该表明该网站正在做一些工作。我使用这些函数来切换所述 div 的可见性( .hidden
在我的 CSS 中只是 display: none;
)
function hideLoading() {
log('hiding')
loadingSpinner.style.display = 'none'
//setTimeout(function (){loadingSpinner.style.display = 'none'}, 10)
//window.getComputedStyle(loadingSpinner) // <-- TRIED FORCING REDRAW
//if (!loadingSpinner.classList.contains('hidden')) {
//loadingSpinner.classList.add('hidden')
//}
}
function showLoading(text) {
log('Showing')
loadingSpinner.innerHTML = text
loadingSpinner.style.display = 'block'
//setTimeout(function (){loadingSpinner.style.display = 'block'}, 10)
//window.getComputedStyle(loadingSpinner)
//if (loadingSpinner.classList.contains('hidden')) {
//loadingSpinner.classList.remove('hidden')
//}
}
function log(s) {
console.log(s)
logDisplay.innerText = s
}
注释掉的代码是我已经尝试过的不同的东西。显示和隐藏功能本身工作正常。我可以看出,由于调用了log()
,所以在正确的时间调用了隐藏和显示函数。 .
据我所知,我有几个实例,网站在客户端上执行一些昂贵/长时间运行的任务,其中任何内容都不应该是异步的(不确定 Array.prototype.forEach()
)。问题是loadingSpinner
仅在昂贵的任务完成后才显示 hideLoading()
立即隐藏它。我确实通过添加 setTimeout()
确认了这一点至hideLoading()
.
function updateDOM() {
showLoading('Updating DOM...') // <--- SHOW
log('Updating DOM') // <--- OTHER LOG MESSAGE
codeContainer.innerHTML = '' // <--- start of long running task
codes.forEach(code => {
if (code.base64 === '') {
backgroundQr.set({value: code.data})
code.base64 = backgroundQr.toDataURL()
}
addCodeElement(codeContainer, code)
});
if (codes.length === 0) {
editingId = -1
} // <--- end of long running task
hideLoading() // <--- HIDE
}
控制台日志顺序正确:
Showing
Updating DOM
hiding
但 log()
的文字都没有写入logDisplay
-元素也不是loadingSpinner
本身在应该出现的时候出现,所以我认为这是一个渲染问题?
这个问题在多个地方都是一致的,而不仅仅是 updateDOM()
功能。
最佳答案
由于昂贵的代码是同步执行的,浏览器太忙于运行它,没有时间将内容渲染到 DOM。您可以采取的一种方法是使用 promises 异步执行昂贵的代码。和 setTimeout函数来延迟昂贵的执行或将其发送到执行队列的末尾。
我创建了下面的代码片段来展示该方法,您需要:
- 微调器处理函数
- 昂贵的执行器函数
- 异步代码运行器
- 将它们组合在一起的主要脚本
下面的代码片段包含两个示例,您可以在两个示例之间切换,一个通过运行 main();
执行成功,另一个通过运行 main(true) 执行失败;
.
function showSpinner() {
document.querySelector('#spinner').style.display = 'block';
}
function hideSpinner() {
document.querySelector('#spinner').style.display = 'none';
}
function executeSuccess() { // runs something expensive that succeeds
return 'data';
}
function executeFailure() { // runs something expensive that fails
throw 'issue';
}
function promiseToRunAsync(executor, ...params) {
return new Promise((resolve, reject) => {
setTimeout(() => {
try { resolve(executor(...params)); }
catch (error) { reject(error); }
}, 1000); // arbitrary time that you can set to anything including 0
});
}
function main(failure = false) {
showSpinner(); // show spinner
promiseToRunAsync(failure ? executeFailure : executeSuccess) // execute anync
.then((results) => {
console.log('yay', results);
document.querySelector('#content').innerHTML = results;
hideSpinner(); // hide spinner in case of success
})
.catch((error) => {
console.log('oops', error);
hideSpinner(); // hide spinner in case of failure
});
// ATTN code here will run before the spinner is hidden
}
main(); // executes the success scenario
// main(true); // executes the failure scenario
#spinner {
display: none;
}
<div id="spinner">Spinning...</div>
<div id="content"></div>
注意:在此处的示例中,我在执行中添加了 1 秒的延迟,只是为了说明发生的情况,但您可能需要设置自己的等待时间或不等待时间完全没有。
关于javascript - 加载微调器 div 未及时渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62190222/