计时器上的jQuery UI进度条

我的页面顶部有一个进度条,我用它来显示用于刷新所有图表的1分钟计时器。 我遇到的问题是它似乎永远不会一致。

function headerBar() { var progressbar = $('#timerBar'); progressbar.progressbar({ value: 0 }); function progress() { var val = progressbar.progressbar('value') || 0; progressbar.progressbar('value', val + 5); if (val < 99) { setTimeout(progress, 3000); } } progress(); } headerBar(); setInterval(function () { headerBar(); }, 60 * 1000); 

它第一次运行正常,但第二次似乎需要1/2的时间,并且每次之后似乎从计数中减去了时间。

这是小提琴

欢呼! 你正陷入一种竞争状态。 由于setTimeout()不保证像setInterval()那样每隔3000ms调用一次(即使它确实如此,你仍然会遇到这个问题),最有可能发生的是你的interval在progress()管理之前调用headerBar()阻止自己添加更多超时! 以下是清除此问题的时间表:

你的进度条是95!

timeout1 – >我最好调用progress()

progress() – >将进度条设置为val + 5 = 100val(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); } 

发表评论后:

看看演示

 (function () { var progressbar; function headerBar() { progressbar = $('#timerBar'); progressbar.progressbar({ value: 0 }); function progress() { var val = progressbar.progressbar('value') || 0; progressbar.progressbar('value', val + 5); if (val < 99) { setTimeout(progress, 3000); } } progress(); } headerBar(); setInterval(function () { progressbar.progressbar('value', 0); }, 60 * 1000); })(); 

你需要一个明确的间隔..像这样

 function headerBar() { var progressbar = $('#timerBar'); progressbar.progressbar({ value: 0 }); function progress() { var val = progressbar.progressbar('value') || 0; progressbar.progressbar('value', val + 5); if (val < 99) { setTimeout(progress, 3000); } } progress(); clearInterval() } headerBar(); setInterval(function () { headerBar(); }, 60 * 1000); 

这里有关于SitePoint的setTimeout的更多示例