欢呼!你遇到了一种竞争状况。由于setTimeout()
不能保证每 3000 毫秒调用一次setInterval()
(即使确实如此,您仍然会遇到此问题),最有可能发生的情况是您的间隔调用headerBar()
之前progress()
设法阻止自己添加更多超时!这是清除此问题的时间表:
你的进度条是 95!
timeout1
-> 我最好打电话progress()
!
progress()
-> 将进度条设置为val + 5 = 100
! val(95) < 99
? 是的!我最好设置一个超时时间再次给自己打电话
interval
-> 你的时间到了!headerBar()
!
headerBar()
-> 我将进度设置为 0,然后开始更多progress()
!
progress()
-> 将进度条设置为 5!超时再给自己打电话!
progress()
-> 将进度条设置为 10!超时再给自己打电话!(哎呀,我从来没有val > 99
停止反复给自己打电话!)
时间流逝...
interval
-> 是时候走得更快了!headerBar()
!
但是你如何解决这个问题?好吧,首先,您需要将progress()
支票更改为使用val + 5 < 99
. 这仍然不会让您免于调用 20 次超时等问题,这些问题需要比您的一个时间间隔更长的时间 - 您需要某种方式来指示您progress()
停止所有进展。
一种方法是添加一些健全性检查headerBar()
:
function headerBar() {
var progressbar = $('#timerBar');
var lastProgress = 0;
progressbar.progressbar({
value: lastProgress
});
function progress() {
var val = progressbar.progressbar('value') || 0;
if (val != lastProgress) {
// Someone's modified the bar! I best stop before I do too much progress!
return;
}
progressbar.progressbar('value', val + 5);
if (val + 5 < 99) {
setTimeout(progress, 3000);
}
}
progress();
}
然而,这是一个非常 hacky 的解决方案。一个更优雅的方法是使用闭包!
var headerBar = (function () {
var inProgress = false;
var progressbar = $('#timerBar'); // Save some trees by calling jQuery selection only once!
return function headerBar() {
if (inProgress) {
clearTimeout(inProgress);
inProgress = false;
}
progressbar.progressbar({
value: 0
});
function progress() {
var val = progressbar.progressbar('value') || 0;
progressbar.progressbar('value', val + 5);
if (val < 99) {
inProgress = setTimeout(progress, 3000);
}
}
progress();
}
})();
但总的来说,您仍然可以通过修改headerBar()
以简单地告诉您何时完成来消除您的间隔(这会在您的计时中引入一个轻微的错误)。
// Pass the jQuery element so you not only have to select it once, but don't depend on the headerBar knowing where to look for it.
var headerBar = (function (progressbar) {
return function headerBar(callback) {
progressbar.progressbar({ value : 0 });
(function progress() {
var newVal = (progressbar.progressbar('value') || 0) + 5;
progressbar.progressbar('value', newVal);
if (newVal < 99) setTimeout(progress, 3000);
else callback();
})();
}
})($('#timerBar'));
function heavyLifting() {
// get stuff, etc
headerBar(heavyLifting);
}