如何在同步JavaScript运行时显示CSS加载程序

如何在同步JavaScript运行时显示CSS加载程序,javascript,html,css,browser,css-animations,Javascript,Html,Css,Browser,Css Animations,根据我自己的经验,并且与一致,在运行JavaScript代码时不会对UI进行更改 示例 当我点击一个按钮“运行脚本”时,我希望加载的动画出现,然后我希望运行一些JavaScript,当JavaScript运行完毕时,我希望加载的动画消失。我创造了一个(可以预见的)失败的世界。代码中最相关的部分是: $('#run-script-btn').on('click', function() { startLoading(); longLoadingScript(10000);

根据我自己的经验,并且与一致,在运行JavaScript代码时不会对UI进行更改

示例
当我点击一个按钮“运行脚本”时,我希望加载的动画出现,然后我希望运行一些JavaScript,当JavaScript运行完毕时,我希望加载的动画消失。我创造了一个(可以预见的)失败的世界。代码中最相关的部分是:

$('#run-script-btn').on('click', function() {
    startLoading();
    longLoadingScript(10000);
    stopLoading();
});
startLoading()
更改CSS以显示加载程序,但在JS完成运行之前,它实际上不会影响UI,此时调用了
stopLoading()
,因此本质上我们从未看到加载图标

我提出的一种解决方法是在
longLoadingScript()
stopLoading()
代码周围放置一个
setTimeout()
,以便让浏览器有时间在
starting()
调用中实际影响UI。工作代码在中,相关部分如下所示:

$('#run-script-btn').on('click', function() {
    startLoading();
    setTimeout(function() {
        longLoadingScript(10000);
        stopLoading();
    }, 100);
});
问题
这是一个好方法吗?是否有更好的/更成熟的模式来处理这种情况?

阅读时,使用a更容易理解:

$('#run-script-btn').on('click', function() {
    startLoading();
    longLoadingScript(10000)
        .then(function () {
            stopLoading();
        });
});

longLoadingScript(ticks) {
    var promise = new Promise(function (resolve, reject) {
        ajax({
            success: function (value?) { promise.resolve(value); },
            fail: function (reason) { promise.reject(reason); }
        })
    });

    return promise;
}

IE(非边缘)将需要一个polyfill()

这实际上是在您的情况下发生的

1) 浏览器根据从服务器接收的HTML和CSS创建呈现树。然后将渲染树绘制到窗口中

2) 因此,当您在DOM中进行任何更改时,例如显示更改(block/none)。需要重新评估渲染树的部分(或完整)。这被称为回流焊

3) 浏览器缓存所有回流/重绘更改,并在主代码块执行完成后执行

4) 案例1-无setTimeout:主代码块执行+回流/重新绘制所有更改。(显示:阻塞,然后无)。没有可见的更改

案例2-使用setTimeout:主代码块执行+回流(显示:block)+事件循环将setTimeout回调推送到调用堆栈-回流将再次发生(显示:无)

它还可以与0毫秒的setTimeout一起使用

回答您的问题:我觉得这个不错,使用它没有任何问题

$('#run-script-btn').on('click', function() {
    startLoading();
    setTimeout(function() {
        longLoadingScript(100);
        stopLoading();
    }, 0);
});
另一种解决方案是使用offsetHeight使元件回流。然而,在我的chrome+osx平台上,它似乎不起作用。在firefox中运行良好

$('#run-script-btn').on('click', function() {
        startLoading();
        var res = $('.page-loading').outerHeight(); // calculates offsetHeight and redraw the element
        longLoadingScript(100);
        stopLoading();
});

参考:

这不是简短的回答,但我会尽量简短

首先,JavaScript是单线程的,所以运行阻塞CPU代码 像
for…loop
while…loop
这样的操作将阻止中的所有内容 你的网页

运行下面截取的命令,查看stackoverflow中的所有内容如何冻结9秒,并且您还将看到
setInterval
也将停止

setInterval(()=>{
console.log(Math.random())
}, 500)
设置超时(()=>{
blocker(9000)//这会使整个网页停止9秒
}, 2500)
功能阻滞剂(ms){
var now=new Date().getTime();
while(true){
如果(新日期().getTime()>now+ms)
返回;
}   

}
我的朋友,你错了,javascript是单线程的,因此运行高CPU消耗操作(如for..loop或同步代码)会阻塞网页中的所有内容,你将无法执行事件单击。