【问题标题】:Stop loop when condition variable (global var) changes in javascript当条件变量(全局变量)在javascript中发生变化时停止循环
【发布时间】:2014-12-05 17:33:13
【问题描述】:

我遇到了一个我无法解决的问题。我在 javascript 中有一个循环,其中要停止的条件变量取决于全局变量。循环开始循环,当我更改该全局变量的值时,它永远不会停止。

stop = false;
var i = 0;
while ((stop == false) && (i<100000)){
    console.log("hi-"+i);
    i++;
}

当循环运行时,如果我停止 = true,它永远不会停止。我不知道这是为什么。

有什么想法吗?

谢谢!

【问题讨论】:

  • 您的代码不会在循环内更改stop
  • JavaScript 是单线程的。将 stop 设置为 true 的事件处理程序(我想)仅在 while 循环完成后才会执行。
  • @hindmost 我在循环外更改了 stop 的值...
  • @user2422900 所以这就是问题所在。应该在循环里面改,不然没有效果
  • 谢谢... 我可以这样做吗? @techfoobar

标签: javascript loops for-loop while-loop


【解决方案1】:

听起来您希望 JS 是多线程的,但事实并非如此,这让某些事情变得很棒。例如,如果 JS 是多线程的,那么下面会做什么呢?

if (x === 3) {
    alert(x);
}

JS 中的答案是“it alerts 3”,但如果 JS 是多线程的,则没有什么可以阻止另一个线程在 if 和 alert 之间编辑 x,因此它不会被很好地定义。

您可以通过使用setTimeoutsetInterval 调度该函数,将控制权返回给浏览器的事件循环,同时确保某些代码将运行。如果您愿意递归的结果是异步的,这也可以让您在没有大量调用堆栈的情况下进行 递归。此外,JS 正在获得一项新功能(生成器和 yield 关键字),这将更容易在中间某处“暂停”一个函数,以便稍后恢复它。

做你想做的最简单的方法是:

var i = 0, running = true;
function iter() {
    if (running && i < 100000) {
        console.log("hi", i++);
        setTimeout(iter, 0);
    }
}
iter();

您还可以在 setTimeout 调用中使用非零时间 - 例如人类的反应时间大约是 200 毫秒,所以如果您只需要它从人类的角度来看是连续的,请将 0 更改为 100;它会给你的电脑更多的呼吸空间。

您也可以使用setInterval,但请注意,如果某些 CPU 密集型函数在一段时间内阻塞其他执行,您将排队等待一个又一个都想执行的相同函数。当 setTimeout 线程调用 setTimeout 时,会有一个 最小延迟,这是由 setTimeout 强制执行的;这不是 setInterval 的情况(它声称调用之间的平均时间是一致的,但没有声称它们之间的最小或最大延迟)。

为了setInterval,您可能希望在某个时间点后停止间隔。在if 上添加if 检查当然会使该函数成为一个什么都不做的空函数,所以它不会浪费太多时间,但如果你想取消调度它,捕获结果setInterval 并将其传递给 clearInterval

【讨论】:

    【解决方案2】:

    JavaScript 本质上是单线程的。一旦代码块开始运行,它将在其他任何事情发生之前运行完成。 IE 将 stop 设置为 true 的事件在 while 循环完成之前不会执行。

    您需要将循环分成多个部分并单独运行每个部分,以允许其他事件发生:

    stop = false;
    var i = 0;
    
    function loopLogic() {
      var tempStop = i + 500;
      while (i < tempStop) {
        //original processing logic
        console.log("hi-" + i);
        i++;
      }
    
      if (!stop && i < 100000)
        window.setTimeout(loopLogic, 0);
    
    }
    window.setTimeout(loopLogic, 0);
    

    这会将函数一次分解为多个 500 个块。持续时间为 0 的 setTimeout 让函数(几乎)立即继续,但会将下一个块放在执行链的底部。这允许其他事件发生,因此将允许将stop 更新为true

    Here's a fiddle 展示了这种方法。

    兼容浏览器中可用的另一种方法是Web Worker,但这已经超出了这个问题的范围。

    【讨论】:

    • 感谢您的回答
    • 我可以这样做吗?想象一下,idk,我希望当我点击身体时停止一段时间......我怎么能实现这样的事情?
    • 嘿,我注意到 if 而不是 console.log("hi-"+i);我调用了一个函数,它不起作用...
    【解决方案3】:

    您可以尝试使用 setInterval.... 将您需要做的事情放入一个函数中并在某个时间间隔调用它...... 看看这里...

    http://jsfiddle.net/o5mnb7jv/1/

    var stop = false;
    var obj = document.getElementById("btn").addEventListener("click", function(){
        stop = true;
    });
    var interval;
    function loop(){
        var result = document.getElementById("result");
        if(!stop){
            result.innerHTML = "Running...";
        }else{
            clearInterval(interval);
            result.innerHTML = "Stopped...";
        }
    }
    interval = setInterval(loop, 500);
    

    【讨论】:

    • 嗯...但我需要该函数执行有限的次数。使用 setInterval 将无限执行,直到停止更改。
    • 您可以存储间隔的实例并使用 clearInterval 停止它......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多