setTimeout()在我的简单计时器脚本中实时工作

时间:2016-01-05 02:29:39

标签: javascript

我正在尝试使用JavaScript进行简单的计时器。一切都好,但setTimeout()只是立即起作用。我该如何解决?

var flag = 0;

function getTimerValue(){
    var val = parseInt(document.getElementById('timer').value,10);
    if (isNaN(val)) {
        val = 0;
    }
    return val;
}

function setTimerValue(newvalue){
        document.getElementById('timer').value = newvalue;
}

function runTimer(){
    if (flag == 0){
        flag = 1;
        while (flag == 1){
            x = getTimerValue()
            if (x < 1){
                setTimerValue(0);
                flag = 0;
            } else{
                setTimeout(setTimerValue(x - 1), 1000);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:2)

它无法正常工作,因为您正在调用setTimerValue函数(这就是它立即执行的原因)。 setTimeout方法需要一个函数引用,因此一个选项是将其更改为:

setTimeout(function () {
  setTimerValue(x - 1);
}, 1000);

或者Paulpro points out,您也可以使用:

setTimeout(setTimerValue, 1000, x - 1);

还值得一提的是,您也可以使用.bind()方法:

setTimeout(setTimerValue.bind(null, x - 1), 1000);

答案 1 :(得分:1)

你的代码错了。如果定时器值非零,则永远循环,不断对事件进行排队以将相同的初始计数器值减1(例如,反复更改7到6,但从不6到5),但因为调度代码永远不会完成,控件永远不会被传回JS事件循环,以允许它处理任何这些事件。

setTimeout不只是“睡眠指定的时间,然后运行此功能”,它不会阻止;它只是安排稍后发生的呼叫,并立即返回。仅当事件循环控制调度事件时才处理调度的调用;由于你的代码永远循环,事件循环永远不会重新获得控制权。

你需要在JS中异步思考;一旦调用异步功能,就不能在回调中的任何地方依赖结果。尝试重构代码以异步方式执行后续工作,因此您实际上会看到更新的值:

function decrementTimerUntilZero() {
    var x = getTimerValue();
    if (x >= 1) {
        setTimerValue(x - 1);
        setTimeout(decrementTimerUntilZero, 1000); // Schedule another decrement
    } else {
        setTimerValue(0);
    }
}
if (getTimerValue() > 0) {
    setTimeout(decrementTimerUntilZero, 1000);
}

如果它是正数,您最初会将其计划为递减,然后每次递减时,如果该值尚未达到零,则计划新的递减。

另一种方法(可能会获得更一致的时序,避免事件循环调度延迟永远不会被弥补)将使用setInterval

var timerinterval = setInterval(function() {
    var x = getTimerValue();
    if (x >= 1) {
        setTimerValue(x - 1);
    } else {
        setTimerValue(0);
        clearInterval(timerinterval);
    }
}, 1000);

在这两种情况下,当你的函数完成时,你基本上放弃了控制,让事件循环做更多的工作,相信你的回调将来可以恢复正常工作。 JavaScript没有sleep函数的概念(按照设计;睡眠会阻止事件循环,直到它完成,冻结浏览器UI);这是间歇性地正常工作的唯一方法。

如果您想了解更多信息,建议您查看What do I do if I want a JavaScript version of sleep()?,了解setTimeout如何运作,为什么它不仅仅是阻塞睡眠等等。