【问题标题】:how to stop the setTimeout recursion如何停止 setTimeout 递归
【发布时间】:2019-10-01 09:53:59
【问题描述】:

我创建了 setTimeout,它有一个名为 run 的回调,在运行中我调用了 console.log(i) 以使用 i++ 打印 I 的值,一旦达到 50,我想清除 setTimeout使用clearTimeout,我再次调用 setTimeout 并运行使其递归,但它不起作用。 有人可以帮助我更好地理解这个概念吗?

let i = 1;

var abc = setTimeout(function run(){
   console.log(i);
if(i==50){
    abc1();
  }  
  i++;
  setTimeout(run,100);
},100);
function abc1(){
     clearTimeout(abc);
}

【问题讨论】:

  • 您遇到的错误是什么?我假设它是run is not defined?
  • 顺便说一句 - 你知道setInterval / clearInterval吗?如果您知道自己想重复运行同一件事直到达到特定条件,那么它们可能是更好的选择。
  • @nightgaunt run is 已定义 - 它是传递给 setTimeout 的命名函数表达式。

标签: javascript recursion settimeout


【解决方案1】:

当您调用 setTimeout 时,您会得到返回的计时器 ID。这正是你在这里所做的:

var abc = setTimeout(function run(){

但是,该 ID 仅在延迟函数执行之前有效。一旦这样做,它是无效的。当您致电setTimeout(run,100); 时,您将获得计时器的 ID。您需要再次捕获它,否则 ID 会丢失,您无法阻止它。

还有最后一个考虑因素 - 使用您当前的代码,即使您要正确捕获调用 abc = setTimeout(run, 100); 的 ID,它仍然不会停止计数器,因为它会尝试停止正在运行的函数(它什么都不做),而不是取消下一个的执行:

let i = 1;

var abc = setTimeout(function run() {
  console.log(i);
  if (i == 50) {
    abc1(); //this will clear the *current* timer 
  } 
  i++;
  abc = setTimeout(run, 100); //this will set the *new* ID 

}, 100);

function abc1() {
  clearTimeout(abc);
}

为了停止执行,您有两个选择。如果你想使用你最初的想法,你需要取消未来的执行它被安排

let i = 1;

var abc = setTimeout(function run() {
  console.log(i);
  abc = setTimeout(run, 100); //this will set the *new* ID 
  if (i == 50) {
    abc1(); //this will clear the *new* timer now
  }
  i++;
}, 100);

function abc1() {
  clearTimeout(abc);
}

或者,您可以完全不使用计时器句柄,只需使用if 条件来确定您是否要安排另一个执行:

let i = 1;

setTimeout(function run() {
  console.log(i);
  if (i != 50) { //until 50 is reached
    abc = setTimeout(run, 100); //schedule a new execution
  }
  i++;
}, 100);

【讨论】:

    【解决方案2】:

    问题在于你的操作顺序。

    if(i==50){
        abc1();
      } 
    

    如果 i 达到 50,将调用函数 abc1() - 清除间隔。

    i++;
    setTimeout(run,100);
    

    在这里您正在重新开始间隔。 您需要将其包装在 else 块中。

    let i = 1;
    
    var abc = setTimeout(function run() {
      console.log(i);
      if (i == 50) {
        abc1();
      } else {
        i++;
        setTimeout(run, 100);
      }
    }, 100);
    
    function abc1() {
      clearTimeout(abc);
    }

    【讨论】:

    • 在这种情况下调用abc1()会产生新的效果。它只会清除已经执行的计时器的句柄。这充其量是多余的,但真的不应该有意识地去做。
    【解决方案3】:
    let i = 1;
    
    var abc = setTimeout(function run(){
      console.log(i);
      if(i<50){
          setTimeout(run,100);
        }  
      i++;
    
    },100);
    

    只有在计时器没有用完时才应该运行超时。

    【讨论】:

      【解决方案4】:

      run() 中的 setTimeout() 未分配给任何变量,因此无法以任何方式清除。

      我想你想要的是覆盖 abc 所以你必须替换:

      setTimeout(run,100);
      

      通过

      abc = setTimeout(run,100);
      

      【讨论】:

        【解决方案5】:

        由于var abc 仅设置一次,在第一次超时时,您只清除第一次超时,这很可能已经完成。

        SetTimeout 返回一个数值,这是一个用于引用该任务的 ID。当你调用clearTimeout时,你必须告知ID你要清除的超时时间,现在你正在通知ID为第一次超时,已经结束,因此无法清除。

        如果您希望清除上次超时,也许您希望始终使用每次超时的 ID 更新 abc,如下所示:

         abc = setTimeout(run,100);
        

        【讨论】:

        • 这很可能已经完成了”它的定义是完整的。它必须至少运行一次(捕获的句柄)才能再运行 50 次。
        • 无关紧要,但在理论上,每次运行的结束并不是执行下一次运行的先决条件。想象一下,如果在setTimeout(run,100); 之后有一条pause() 指令。执行理论上不会有任何问题(除了暂停 50 条指令,但是哦……)
        • "每次运行的结束不是执行下一次运行的先决条件" 但是你先延迟一个函数,然后你就得到一个句柄。除非在该句柄上运行 clearTimeout,否则延迟函数将执行。如果它执行,那么运行clearTimeout 从延迟函数 意味着句柄已经无用 - 计时器被触发。如果计时器被取消,则延迟函数不会运行,因此它不会调用clearTimeout。在所有情况下,我都可以看到从延迟功能中取消计时器是无用的,而不是有时无用。
        【解决方案6】:

        这是一种奇怪的定时循环方式,但你只需要清除(实际上在这种情况下不是,但我还是喜欢这样做,因为一旦你不再使用它们就释放资源是一个好习惯)在创建新超时之前(通过跟踪 abc 句柄完成)并在给定条件下在clear 之后返回:

        let i = 1;
        
        let abc = setTimeout(
          function run(){
            console.log(i);
            if(i==50){
              abc1();
              return;
            }
            abc1();
            i++;
            abc = setTimeout(run,100);
          },
          100
        );
        
        function abc1(){
          clearTimeout(abc);
        }

        【讨论】:

        • 嗨,这段代码运行良好,你能帮我理解为什么你两次调用 abc1
        • 此代码有效但不正确。它不继续的原因是因为return 将在安排新函数之前退出该函数 - 调用abc1(因此调用clearTimeout)完全是多余的并且对代码没有影响。它只会清除当前正在运行的句柄,这是一个空操作。
        【解决方案7】:

        你需要在调用 abc1 函数后添加 return。您清除了超时,但代码仍在运行并再次调用 setTimeout(run,100)。

                let i = 1;
        
        var abc = setTimeout(function run(){
           console.log(i);
        if(i==50){
            abc1();
            return;
          }  
          i++;
          setTimeout(run,100);
        },100);
        function abc1(){
             clearTimeout(abc);
        }
        

        【讨论】:

        • return 使调用abc1 变得多余。清除旧手柄不会影响任何事情。
        猜你喜欢
        • 2022-09-27
        • 1970-01-01
        • 2013-05-18
        • 1970-01-01
        • 1970-01-01
        • 2021-02-12
        • 1970-01-01
        相关资源
        最近更新 更多