显示加载处理器的异常行为
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>
也许我应该改进我的示例。
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>