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

时间:2015-09-24 03:42:21

标签: javascript jquery promise loading deferred

也许我应该改进我的榜样。

    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,之后隐藏加载。但是,装完后会显示并隐藏......

3 个答案:

答案 0 :(得分:1)

问题是CGRect函数,它将执行线程保持5秒钟。

在javascript中,脚本执行和ui刷新都发生在一个线程中,因此如果您运行脚本直到完成,UI将不会更新。

所以你的apply函数在调用show之后很快就会持有执行线程,因此不会执行UI中元素的显示。

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

&#13;
&#13;
while
&#13;
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();
&#13;
&#13;
&#13;

但是jQuery-ish解决方案就像

一样简单

&#13;
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<div id="loading" style="display:none">Loading</div>
&#13;
function start() {
  return $("#loading").show().delay(5000).hide(0);
}

start();
&#13;
&#13;
&#13;

答案 1 :(得分:1)

@ jfriend00的答案应该有效。但使用window.setTimeout是不可靠的。刚刚使用CPU速度慢/内存不足的VM进行检查,window.setTimeout 15ms无法正常工作......

要获得更可靠的方法,您可以尝试使用window.requestAnimationFrame来保证重绘/重排事件的发生。

&#13;
&#13;
$(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);
});
&#13;
<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>
&#13;
&#13;
&#13;

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

&#13;
&#13;
$(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);
});
&#13;
<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>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

也许您应该检查.delay()功能。

以下是使用它的示例:

&#13;
&#13;
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);
&#13;
#loading {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background: #ccc;
  display: none;
}
&#13;
<div id="loading"></div>

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