显示加载处理器的异常行为

Abnormal behavior to show loading processor

也许我应该改进我的示例。

    function doSomethingHeavy() {
        // emulate do something heavy
        var now = new Date().getTime();
        while (new Date().getTime() < now + 5000) {
            // do nothing
        }
    }

    $("#testButton").bind("click.performTest", function () {
        $("#loading").show();
        doSomethingHeavy();
        $("#loading").hide();
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button type="button" id="testButton">Perform Test</button>
<div id="loading" style="display:none" >Loading</div>

我假设调用显示加载然后调用 doSomethingHeavy,然后隐藏加载。但是,加载完成后显示和隐藏...

问题是 apply 函数,它使执行线程保持 5 秒。

在 javascript 中,脚本执行和 ui 刷新都发生在单个线程中,因此如果您是 运行 脚本,直到它完成 UI 将没有得到更新。

因此您的 apply 函数在调用显示后不久就持有执行线程,因此不会执行 UI 中元素的显示。

因此,要延迟项目的执行,而不是使用硬编码的 while 基于循环的延迟,请使用计时器,如下所示。

function show() {
  return $("#loading").show().promise();
}

function hide() {
  return $("#loading").hide().promise();
}

function start() {
  return $.when(show()).then(apply).then(hide);
}

function apply() {
  var deferred = $.Deferred();
  var now = new Date().getTime();
  setTimeout(function() {
    deferred.resolve();
  }, 5000)
  return deferred.promise();
}

start();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div id="loading" style="display:none">Loading</div>


但是 jQuery 式的解决方案就像

一样简单

function start() {
  return $("#loading").show().delay(5000).hide(0);
}

start();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div id="loading" style="display:none">Loading</div>

也许你应该检查一下 .delay() 函数。

这是一个使用它的例子:

var DELAY = 1000,
  ANIMATION_DURATION = 500;

var loading = {
  elm: function() {
    return $('#loading').delay(DELAY);
  },
  show: function() {
    loading.elm().fadeIn(ANIMATION_DURATION);
  },
  hide: function() {
    loading.elm().fadeOut(ANIMATION_DURATION);
  }
};

loading.show();

setTimeout(loading.hide, 2000);
#loading {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: #ccc;
  display: none;
}
<div id="loading"></div>

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>

@jfriend00 的回答应该可以。但是使用 window.setTimeout 是不可靠的。刚刚检查过使用速度慢 CPU/内存不足的虚拟机,window.setTimeout 15 毫秒不工作...

为了更可靠的做法,您可以尝试使用window.requestAnimationFrame,它可以保证重绘/回流事件的发生。

$(document).ready(function () {

    function showLoading() {
        $("#loading").show();
    }

    function hideLoading() {
        $("#loading").hide();
    }

    function performTest() {
        showLoading();
        window.requestAnimationFrame(function () {
            // redraw/ reflow occurred for #loading to show...
            window.requestAnimationFrame(function () {
                doSomethingHeavy(4000);
                hideLoading();
            });
        });
    }

    function doSomethingHeavy(processTime) {
        // emulate do something heavy
        var start = +new Date();
        while (+new Date() - start < processTime) {
            // do nothing
        }
    }

    $("#testButton").bind("click.performTest", performTest);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button type="button" id="testButton">Perform Test</button>
<div id="loading" style="display: none">Loading... (this will disappear in 4 seconds)</div>

使用嵌套 window.requestAnimationFrame 包装 doSomethingHeavy 很奇怪而且不直观,也许值得使用 promise 模式...

$(document).ready(function () {

    function showLoading() {
        var deferred = $.Deferred();
        window.requestAnimationFrame(function () {
            $("#loading").show();
            // ensure the redraw/ reflow occurred, then resolve the callback
            window.requestAnimationFrame(function () {
                deferred.resolve();
            });
        });
        return deferred.promise();
    }

    function hideLoading() {
        var deferred = $.Deferred();
        window.requestAnimationFrame(function () {
            $("#loading").hide();
            // ensure the redraw/ reflow occurred, then resolve the callback
            window.requestAnimationFrame(function () {
                deferred.resolve();
            });
        });
        return deferred.promise();
    }

    function performTest() {
        $.when(showLoading()).then(function () {
            doSomethingHeavy(4000);
        }).done(hideLoading);
    }

    function doSomethingHeavy(processTime) {
        // emulate do something heavy
        var start = +new Date();
        while (+new Date() - start < processTime) {
            // do nothing
        }
    }

    $("#testButton").bind("click.performTest", performTest);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button type="button" id="testButton">Perform Test</button>
<div id="loading" style="display: none">Loading... (this will disappear in 4 seconds)</div>