1

我的页面顶部有一个进度条,用于显示用于刷新所有图表的 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 的时间,之后每次似乎都从计数中减少时间。

这是小提琴

4

3 回答 3

3

欢呼!你遇到了一种竞争状况。由于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);
}
于 2013-05-24T17:54:17.707 回答
1

根据您的评论:

看演示

(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);
})();
于 2013-05-24T17:17:07.153 回答
0

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

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 示例在这里

于 2013-05-24T17:15:41.413 回答