为什么浏览器的重排不会被触发,而Javascript正在被执行?

时间:2016-07-07 16:17:11

标签: javascript jquery html css browser

在我正在开发的应用程序的UI中,我一直在尝试显示一个" loader"特定(同步)处理开始之前的div,并在处理结束后隐藏它。但是,在整个处理过程中,加载器根本不会出现。

我发现浏览器会尝试通过尽可能消除不必要的回流来优化渲染过程。有一些方法可以手动触发回流过程(对于像我这样的情况),但我还没有设法让它们中的任何一个工作。您可以在下面找到一个最小的示例,其中offsetHeight的计算用于触发重排,但TEST div根本没有出现。

<html>
<head>
<script src="https://code.jquery.com/jquery-2.2.4.js"></script>
</head>
<body>
<div id="test" style="display:none; background-color:red; height:500px">TEST</div>

<script>
    function reflow() {
        var t = $("#test")[0].offsetHeight;
        $(window).trigger('resize');
        window.getComputedStyle($("#test")[0], null);
        $("#test").focus();
    }

    $("#test").show();
    reflow();
    console.log("Processing started");
    var sum = 0;
    for(i = 0; i < 100000000; i++) {
        sum += i;
    }
    console.log("Processing ended");
    $("#test").hide();
<script>
</body>
</html>

使用JSFiddle here

尝试强制重排的一些方法如下(正如您在脚本中看到的那样):

  • offsetHeight计算元素
  • 窗口调整大小
  • window.getComputedStyle()
  • 元素焦点

注意:我知道可以通过添加超时来解决它。但是,我想找到一种强制重排的方法,因为超时是一个&#34; hack&#34;并且不适合此功能。

2 个答案:

答案 0 :(得分:0)

使用带有“0”参数的setTimeout进行等待,这将强制它停止足够长的时间以使你的显示/隐藏起作用。

https://jsfiddle.net/o3y60e0L/3/

$("#test").show();
var t = $("#test")[0].offsetHeight;
console.log("Processing started");
setTimeout(function() {
    var sum = 0;
    for(i = 0; i < 1000000000; i++) {
        sum += i;
    }

    console.log("Processing ended");
    $("#test").hide();
}, 0);

答案 1 :(得分:0)

最终看来,即使您手动触发重新流动事件,如我的代码所示,此事件也会添加到事件队列中。由于每个窗口只有1个javascript线程,因此只有在执行代码完成时才会处理这些事件。

即使我找不到这种行为的官方文档,我也无法使用任何提议的技术触发同步重排(当某些代码正在执行时)。因此,唯一的解决方案似乎是添加一个小超时,以便线程在一小段时间内处于空闲状态,并且可以在开始执行剩余代码之前处理reflow事件(如@Dan Smolinske所建议的那样)。

为了避免困惑不同的功能,可以创建一个新方法executeWithLoader,如下所示:

function executeWithLoader(callback) {
    $("#test").show();
    setTimeout(function() {
        callback();
        $("#test").hide();
    }, 50, this);
}

从类中调用此函数,按以下方式执行处理:

function processing() {
    console.log("Processing started");
    var sum = 0;
    for(i = 0; i < 100000000; i++) {
        sum += i;
    }
    console.log("Processing ended");
}
executeWithLoader(processing);

我现在将此作为已接受的答案留下,但如果将来有任何答案描述了触发重新流动的成功方法,我会将其切换。