Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/365.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
一个更好(希望)的JavaScript倒计时器_Javascript - Fatal编程技术网

一个更好(希望)的JavaScript倒计时器

一个更好(希望)的JavaScript倒计时器,javascript,Javascript,在我们的应用程序中,我们需要一个健壮的倒计时计时器。当计时器倒计时到零时,我们将用户移动到下一页 这里有很多关于用JavaScript制作倒计时的问题。我已经筛选了很多,查看了很多代码示例,尝试了很多插件,但在这个测试用例中,所有这些都失败了:如果调整计算机系统时钟,所有这些计时器都会出错(增加时间、减少时间,或者干脆冻结)。原因是,他们中的大多数人的逻辑基础是保存一些初始启动时间,然后在某个时间间隔(通过setTimeout或setInterval)获取当前时间,并在其与启动时间之间进行差异。

在我们的应用程序中,我们需要一个健壮的倒计时计时器。当计时器倒计时到零时,我们将用户移动到下一页

这里有很多关于用JavaScript制作倒计时的问题。我已经筛选了很多,查看了很多代码示例,尝试了很多插件,但在这个测试用例中,所有这些都失败了:如果调整计算机系统时钟,所有这些计时器都会出错(增加时间、减少时间,或者干脆冻结)。原因是,他们中的大多数人的逻辑基础是保存一些初始启动时间,然后在某个时间间隔(通过setTimeout或setInterval)获取当前时间,并在其与启动时间之间进行差异。调整系统时间时,“当前”时间可以是开始时间前一小时或几天,也可以是几小时或几天

因此,我提出了以下代码来尝试处理这些系统更改场景。我要做的主要事情是检查我的启动和当前之间的“差异”是否为负(或者大于大约一个小时以处理自动夏令时调整),仅使用滴答时间间隔作为近似值。另外,在每次滴答声时,将开始时间重置为当前时间,以便经过的时间是差异之间的时间之和,而不仅仅是初始开始时间和当前时间之间的差异。有人看到这种方法有什么缺陷吗

var timeLeft = 60000, // time left in ms, 1 minute for this example
    startTime, 
    totalElapsedTime = 0,
    TICK_INTERVAL = 500; // the setTimeout interval


var timerTick = function () {

    var now = new Date(),
        elapsedTime = now.getTime() - startTime.getTime();

    // if the elapsed time was positive and less than approximately an hour, then add the elapsed time to the total
    // otherwise, add the TICK_INTERVAL, which we know is the theoretical minimum between timerTick() calls

    totalElapsedTime = (elapsedTime > 0 && elapsedTime < 3590000) ? totalElapsedTime + elapsedTime : totalElapsedTime + TICK_INTERVAL;

    // reset start time 
    startTime = now;

    // there is time left, so set up another tick
    if (totalElapsedTime < timeLeft) {

        // update the html that is displaying remaining time

        setTimeout(timerTick, TICK_INTERVAL);          

    }
    else {

        // time ran out, so do whatever you do when it runs out            

    }
}


// start the timer
startTime = new Date();
setTimeout(timerTick, TICK_INTERVAL);
var timeLeft=60000,//剩余时间(毫秒),本例为1分钟
开始的时候,
totalElapsedTime=0,
勾选间隔=500;//设置超时时间间隔
var timerTick=函数(){
var now=新日期(),
elapsedTime=now.getTime()-startTime.getTime();
//如果经过的时间为正值且小于约一小时,则将经过的时间添加到总时间中
//否则,添加TICK_间隔,我们知道它是timerTick()调用之间的理论最小值
totalElapsedTime=(elapsedTime>0&&elapsedTime<3590000)?totalElapsedTime+elapsedTime:totalElapsedTime+TICK_间隔;
//重置开始时间
开始时间=现在;
//还有时间,所以再打勾
如果(总延时<延时){
//更新显示剩余时间的html
setTimeout(timerTick,TICK_INTERVAL);
}
否则{
//时间不多了,所以在时间不多的时候做你该做的
}
}
//启动计时器
开始时间=新日期();
setTimeout(timerTick,TICK_INTERVAL);

为什么以下内容不适用于您

var timeleft = 60000,
    tick = 1000,
    intervalID = window.setInterval(function () {
        timeleft = timeleft - tick;
        if (timeleft <= 0) {
            // clear the interval
            clearInterval(intervalID);

            // do something
        }
    }, tick);

简单地执行
setInterval
1秒并在每次调用函数时减少一个计数器有什么错?如果您想尝试一些不同的方法,您可以使用一些AJAX调用或其他方法从服务器查询时间。我想服务器时间可以保证保持一定的静态(除了某些非常特殊的情况)。我考虑过这一点,但我们正在向用户显示计时器,秒数正在倒计时。如果调用的ajax由于某种原因被延迟,我会担心用户会看到计时器冻结或跳转。不必担心,
setInterval
将按照您指定的时间间隔准确地(或多或少地)调用。例如,即使AJAX调用需要5000毫秒,您的函数也会被调用5次(在本例中可能会重叠)。当然,您永远不会同步进行AJAX调用,因此这不是一个真正的问题。
setInterval
并不意味着您的函数将以您指定的时间间隔运行。它所做的只是将函数调用添加到执行队列中,并在所有其他执行代码运行后立即运行。实际上,这意味着您的函数将在一秒钟后运行,因此计时器将使用此逻辑漂移。不确切地说,对您函数的每次调用都将按固定的时间间隔进行安排,因此,即使您的函数需要500毫秒,下一次对函数的调用也将在前一时间+滴答声(因此500毫秒后)进行。所以会有一点漂移(无论您采取什么方法,这都是不可避免的),但它只是局部的(函数调用之间)。这不会影响未来的通话。我正在向用户直观地显示秒数倒计时。因此,间隔需要小于1000,否则计时器将向用户显示为“跳过”。使用setInterval会导致问题,因为它会不断地添加函数调用。这里更清楚地解释了使用setTimeout的情况:。实际上,您希望在这里使用setInterval,而不是setTimeout,因为setInterval不关心函数需要多长时间。它永远不会偏离你给它的初始间隔。我在这里举了一个例子来证明,即使您的函数花费的时间比间隔长,您也会再次被调用,并且间隔总是在正确的时间触发:确保在jsbin示例中打开控制台以查看当前时间(秒值)和打印的剩余间隔时间。即使我在函数的下面做了一些无用的计算,也不会发生跳过。希望这有帮助。
var timeleft = 60000,
    tick = 1000;

window.setTimeout(function timerFn() {
    timeleft = timeleft - tick;
    if (timeleft > 0) {
        // set the next timeout
        setTimeout(timerFn, tick);
    } else {
        // do something
    }
}, tick);