Javascript 加载微调器div未及时渲染
TL;医生:Javascript 加载微调器div未及时渲染,javascript,html,css,Javascript,Html,Css,TL;医生: loadingSpinnerdiv在昂贵代码之前打开,在昂贵代码之后关闭 showLoading()和hideLoading()都调用log(),将消息写入console.log()和元素的innerHTML DOM中的loadingSpinner和log消息在昂贵的代码完成之前不会显示,但是console.log()消息在应该显示的时候会显示 我引用了一个存储在loadingSpinner中的div,它只是一个位于所有其他内容之上的框,应该表明站点正在做一些工作。我使用这些
div在昂贵代码之前打开,在昂贵代码之后关闭loadingSpinner
和showLoading()
都调用hideLoading()
,将消息写入log()
和元素的console.log()
innerHTML
- DOM中的
和log消息在昂贵的代码完成之前不会显示,但是loadingSpinner
消息在应该显示的时候会显示console.log()
我引用了一个存储在
loadingSpinner
中的div,它只是一个位于所有其他内容之上的框,应该表明站点正在做一些工作。我使用这些函数切换所述div的可见性(。hidden
只是display:none;
在我的CSS中)
函数hideLoading(){
日志('隐藏')
loadingSpinner.style.display='none'
//setTimeout(函数(){loadingSpinner.style.display='none'},10)
//getComputedStyle(loadingSpinner)//我认为您的问题在于代码是异步的。
在启动forEach循环的那一刻,代码会一直持续到hideLoading,而forEach循环仍在执行,因此您将永远看不到加载程序,因为您会依次调用showLoading和hideLoading
尝试如下更改代码:
function updateDOM() {
showLoading('Updating DOM...') // <--- SHOW
log('Updating DOM') // <--- OTHER LOG MESSAGE
codeContainer.innerHTML = '' // <--- start of long running task
for (const code of codes) {
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
}
函数updateDOM(){
showLoading('Updating DOM…')/由于昂贵的代码是同步执行的,浏览器正忙于运行它,找不到任何时间将内容呈现给DOM。可以采取的一种方法是使用和函数异步执行昂贵的代码,以延迟昂贵的执行或将其发送到执行队列的末尾
我已经创建了下面的代码段,其中显示了该方法,您将需要:
- 微调器处理函数
- 昂贵的执行器函数
- 异步代码运行程序
- 你的主脚本把它们放在一起
下面的代码段包含两个示例,您可以在这两个示例之间切换,一个通过运行main();
,执行成功执行,另一个通过运行main(true);
,执行失败执行
函数showSpinner(){
document.querySelector(“#微调器”).style.display='block';
}
函数hideSpinner(){
document.querySelector(“#微调器”).style.display='none';
}
函数executeSuccess(){//运行一些代价高昂的操作并成功
返回“数据”;
}
函数executeFailure(){//运行一些昂贵的操作,但失败了
抛出"问题",;
}
函数promiseToRunAsync(执行器,…参数){
返回新承诺((解决、拒绝)=>{
设置超时(()=>{
尝试{解析(执行器(…参数));}
捕获(错误){拒绝(错误);}
},1000);//可以设置为包括0在内的任意时间
});
}
主功能(故障=错误){
showSpinner();//显示微调器
promiseToRunAsync(失败?executeFailure:ExecuteSucces)//执行anync
。然后((结果)=>{
console.log('yay',结果);
document.querySelector(“#content”).innerHTML=results;
hideSpinner();//成功时隐藏微调器
})
.catch((错误)=>{
log('oops',错误);
hideSpinner();//在出现故障时隐藏微调器
});
//此处的ATTN代码将在隐藏微调器之前运行
}
main();//执行成功场景
//main(true);//执行故障场景
#微调器{
显示:无;
}
旋转。。。
您可以附加JSFIDLE或其他任何东西,以便我们可以尝试帮助您。感谢整个updateDOM
函数似乎在执行同步代码,浏览器可能太忙了,无法在屏幕上显示任何内容。您考虑过异步执行昂贵的代码吗?@GhassenLouhaichi我考虑过了尝试将整个昂贵的代码放在它自己的setTimeout
中,作为一种简单的异步方式,这也没有帮助。你能在问题中告诉我们,或者可能将我们链接到JSFIDLE吗?理论上,这应该行得通。不幸的是,这似乎没有什么区别。forEach上的MDN页面对我来说非常混乱,所以我仍然很困惑我不确定它是异步还是非异步。问题是,当我在hideLoading()中添加超时时,我确实看到了微调器
但它只在昂贵的代码运行后才开始显示,所以除非我解释错误,否则这不可能是问题所在。是的,你是对的。我的建议是基于在forEach上执行某项操作时使用等待-这两者不一起工作。但这里不是这种情况。这是有效的,我不明白为什么它会导致问题首先,假设所有JS都同步运行。我认为这会改变微调器的可见性,然后运行昂贵的代码并阻止线程。我猜这一定是由于浏览器渲染管道中的某些优化,使得它决定在开始执行昂贵的JS之前不渲染…DOM更新过程ess与JS执行线程是分开的,因此当浏览器忙于后者时,它没有时间处理前者。
function updateDOM() {
showLoading('Updating DOM...') // <--- SHOW
log('Updating DOM') // <--- OTHER LOG MESSAGE
codeContainer.innerHTML = '' // <--- start of long running task
for (const code of codes) {
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
}