clearTimeout 不工作:参数未定义(即使它是在全局范围内定义的)

clearTimeout not working: parameter undefined(even though it's defined in the global scope)

我的 setTimeout() 函数有效,但我的 clearTimeout() 无效。即使我有一个 'if' 语句应该 运行 clearTimeout 函数,一旦我的变量 'secs' 小于 0,计时器就会继续倒计时为负数。当我在控制台中输入我的变量名 'secs' 时,我得到了未定义,即使它被定义为我的 setTimeout 调用的函数中的参数。我不知道我做错了什么。有人可以帮忙吗?

我的完整代码在 https://codepen.io/Rburrage/pen/qBEjXmx;

这是 JavaScript 片段:

function startTimer(secs, elem) {
    t = $(elem);
    t.innerHTML = "00:" + secs;

    if(secs<0) {
        clearTimeout(countDown);
    }
    secs--;
    //recurring function
    countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);

}

添加一个条件来调用递归函数,如下所示。

if (secs < 0) {

   secs = secsInput;
 }

   //recurring function
    countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);

对于倒数计时器,我建议改用 setIntervalclearIntervalsetInterval会为您重复运行回调函数。它可能看起来像这样:

let countdown;

function startTimer(secs, elem) {
  countdown = setInterval(function(){
    t = $(elem);
    t.innerHTML = "00:" + secs;

    secs--
    if (secs < 0) {
      clearInterval(countdown);
    }
  }, 1000);
}

在你的情况下,使用 setIntervalclearInterval 更方便。

要保留 setTimeoutclearTimeout 功能,您应该在 if 语句中添加 return

function startTimer(secs, elem) {
    t = $(elem);
    t.innerHTML = "00:" + secs;

    if(secs<0) {
        clearTimeout(countDown);
        return;
    }
    secs--;
    //recurring function
    countDown = setTimeout('startTimer('+secs+',"'+elem+'")', 1000);

}

当您调用 clearTimeout(countDown) 时,countDown 指的是 previous 超时,它已经超时了。它不会阻止尚未开始的人。你可以不重新设置超时,比如

 if(!/*finished*/) setTimeout(startTimer, 1000, secs, elem);

所以我认为有 4 个事件必须由计时器处理:

  1. 测验开始
  2. 测验结束
  3. 计时器用完
  4. 玩家回答问题

这可以通过一个返回带有一些选项的对象的函数来解决。 createTimer可以用来设置定时器的参数。

点 1. 将是 timer.start() --> 将使用参数

启动计时器

第 3 点可以通过计时器用完时将调用的回调来解决 --> createTimer(5,'display', ()=>{ // your code goes here })

第 2 点可以通过 --> timer.stop()

实现

第 4 点需要在没有 运行 out timer.reset()

的情况下重置计时器

此外,间隔不在全局范围内,因此您可以有多个具有不同设置的计时器,并且它们不会相互干扰

// function for creating the timer
function createTimer(seconds, cssSelector, callbackOnTimeout) {
    // interval the timer is running
    let interval;
    // the html node where innerText will be set
    const display = document.getElementById(cssSelector)
    // original seconds passt to createTimer needed for restart
    const initSec = seconds

    // starting or continuing the interval
    function start() {

        // setting interval to the active interval
        interval = setInterval(() => {

            display.innerText = `00:${seconds}`;

            --seconds;
            if (seconds < 0) {
                // calling restart and callback to restart
                callbackOnTimeout()
                restart()
            }
        }, 1000);

    }

    // just stopping but not resetting so calling start will continue the timer
    // player takes a break
    function stop(){
        clearInterval(interval)
    }

    // opted for a restart and not only a reset since it seemed more appropriate for your problem
    function restart(){
        clearInterval(interval)
        seconds = initSec
        start()
    }
    // returning the object with the functions
    return {
        start: start,
        stop:   stop,
        restart:  restart
    }
}

// example for creating a timer
const timer1 = createTimer(5,'display',()=>{
    console.log(`you where to slow ohhh...`)
})

// calling the timer
timer1.start()