javascript定时器

标签 javascript

我正在尝试使以下 javascript 计时器仅通过单击一个按钮即可执行两个功能 - 一旦计时器启动,请单击;再次点击;它停止了。第三次点击它再次开始,依此类推。我在这里做错了什么?非常感谢您。

    <html>
<head>
    <script type="text/javascript">
        var c=0;
        var t;
        var timer_is_on=0;

        function timedCount()
        {
            document.getElementById('txt').value=c;
            c=c+1;
            t=setTimeout("timedCount()",1000);
        }

        function doTimer()
        {
            if (!timer_is_on)
            {
                timer_is_on=1;
                timedCount();
            }
        }

        function stopCount()
        {
            clearTimeout(t);
            timer_is_on=0;
        }
        function both(){
            doTimer();
            stopCount();
        }
    </script>
</head>

<body>
    <form>
        <input type="button" value="Start count!" onclick="doTimer" />
        <input type="text" id="txt" />
        <input type="button" value="Stop count!" onclick="stopCount()" />
    </form>
<p>
Click on the "Start count!" button above to start the timer. The input field will count forever, starting at 0. Click on the "Stop count!" button to stop the counting. Click on the "Start count!" button to start the timer again.
</p>
</body>
</html>

最佳答案

您没有描述实际问题,所以我不太确定该用什么来回应,但这里有一些可能有用的注释。

timedCount 函数是准定时递归的。如果你喜欢 continuation passing style,这很酷,但这不是必需的,可能比它需要的 JavaScript 更令人困惑,并且会在没有尾递归堆栈清理的语言中浪费一些资源(堆栈框架)(不知道 JS 是否有那个或不是)。

因为这是一个重复的函数执行,你可以使用 setInterval而不是 setTimeout,并有一个重复的函数调用来检查它是否应该递增并重新显示计数......像这样:

var c=0;
var timer_is_on=false;

function displayCount() {
    document.getElementById('txt').value=c;
}

function count() {
    if(timer_is_on) {
        c=c+1;
        displayCount();
    }
}

var interval = setInterval(count,1000);

现在,解决问题的单按钮部分。假设有一个按钮:

<input type="button" value="Start count!" onclick="toggle" />

当我们点击它时,我们希望“值”属性发生变化,我们希望它翻转 timer_is_on 变量。让我们创建一个函数来完成所有这些事情:

function toggle() {
    if(timer_is_on) {
       timer_is_on = false;
       this.value = "Start count!";  // `toggle` is invoked by the button's event handler, so `this` is the button
    } else {
       timer_is_on = true;
       this.value = "Stop count!";
    }                   
}

所以...计数总是每 1000 毫秒执行一次,但它只在 timer_is_on 时才执行任何操作,而 timer_is_on 是真还是假由 toggle 控制,它附在我们的按钮上。我认为稍微简单一些。

更新

如果我们不想函数count 总是在后台运行怎么办?正如 Tom Tu 指出的那样,这可能代表 CPU 开销。我不确定它是否是一个可衡量的(或者它代表浏览器可能运行以执行其自己的 UI 更新的计时器之外的任何开销),但它在某些平台上可能很重要,因此可能值得解决。

虽然我们正在完善,但我不太喜欢自己通过标签属性附加事件处理程序,或者如果可以避免的话,也不太喜欢将变量放在全局/窗口范围内,所以我可能会包装所有相关的计数器设置/在一个大的 setupCounter 函数中处理 JavaScript,并使用 DOM 选择和 JavaScript 将 toggle 函数附加到输入按钮的 onclick 事件。我可能也会尝试每次只运行一次 document.getElementById 查找。

因此,假设按钮输入具有 id startstop,但在其他方面假设类似的标记。我可能会做这样的事情:

function setupCounter() { 
    var c=0,
        interval,
        counter_display = document.getElementById('txt'),
        button = document.getElementById('startstop');

    function display_count() {
        counter_display.value = c;
    }

    function count() {
        c=c+1;
        display_count();
    }

    function toggle() {
       if(!interval)
          interval = setInterval(count,1000);
          button.value = "Stop count!";
       else {
          clearInterval(interval);
          interval = false;
          button.value = "Start count!";
       }
    }

    button.onclick = toggle;
}

然后您可以在声明 counter_display 和 startstop 元素后的某个时间在文档中调用 setupCounter,或者将其分配给 window.onload 事件或通过它类似于 jQuery 的 $(document).ready()

关于javascript定时器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5767022/

相关文章:

javascript - Backbone .js。正确设置更改事件

javascript - Html 地理定位在我的移动网络应用程序上不起作用 | Spring MVC

javascript - 如何使两个或多个 html 元素在可编辑区域中表现为一个单元

javascript - Messenger 共享导致 "Messenger Extensions unexpected error"

javascript - React 中的静态方法

javascript - 如何在 Closure Compiler 中将 node_modules 定义为 extern?

javascript - 在 javascript 中检测 Mountain Lion (OS X 10.8)?

javascript - 带有元音变音 (ü) 的域上的 location.href 报告不同的域

javascript - 如何使用 async-await 停止执行下一个函数?

javascript - 如果加载失败,是否有更好的方法在 app.js 脚本标记上添加 onerror 回调?