使用break在点击时停止for循环

4
我有一个简单的1-20循环。我想要做的是通过按钮点击停止循环。我所做的是,我放了一个条件,一旦点击按钮变量stop的值将被更改为1,这将触发break。但是该值未被更改。

var stop = 0;
for(let i = 1; i <= 20; i++){
  
  if(stop === 1){
    break;
  }
  
  setTimeout(function(){
    $('ul').append('<li>'+ i +'</li>');
  },i * 500);
}

$('button').click(function(){
    stop = 1;
});
ul li{
  list-style-type: none;
  float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>

<br>
<button>stop</button>


因为你的 setTimeout 已经全部被触发了。 - kevinSpaceyIsKeyserSöze
在你的 setTimeout 前面添加一个 console.log(i),你就会明白我的意思。 - kevinSpaceyIsKeyserSöze
如果我将我的if语句更改为if (i === 3) { break; },它就可以工作。 - user123
是的,因为这样你就在3上打破了循环。 - kevinSpaceyIsKeyserSöze
这就是我想要做的——打破循环。 - user123
对不起,先生。我改正我的错误了。 - user123
5个回答

6

在你按下停止按钮之前就已经调用了20个setTimeout函数。
解决此问题的众多方法之一是在执行setTimeout函数时检查stop变量。

var stop = 0;
for (let i = 1; i <= 20; i++){
  setTimeout(function(){
    console.log(stop);
    if (stop !== 1) {
      $('ul').append('<li>'+ i +'</li>');
    }
  },i * 500);
}

$('button').click(function(){
    stop = 1;
});
ul li{
  list-style-type: none;
  float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>

<br>
<button>stop</button>


编辑:

你问如何停止for循环。按照现有的写法,你不能停止它。
以下是我会用setTimeout实现“停止”循环的方法。
你也可以使用setInterval(查看Сергей Петрашко的答案了解如何操作)。
在这里阅读它们之间的区别)。

var stop = false;

function addNumberAndCallNext(number, max) {
    if (!stop && number <= max) {
        $('ul').append('<li>'+ number +'</li>');
        setTimeout(addNumberAndCallNext.bind(null, ++number, max), 500);
    }
}

addNumberAndCallNext(1, 20);

$('button').click(function(){
    stop = true;
});
ul li {
  list-style-type: none;
  float: left;
  padding-right: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>

<br>
<button>stop</button>


变量仍然没有改变。 - user123
2
你是在指 stop 变量吗?我在 if 检查之前添加了 console.log(stop)。你可以看到它会变成 1。当然,函数仍然会执行,因为我们在一开始就设置了它们的超时时间。 - Maor Refaeli
是的先生,您说得对。我只是在想为什么“stop”的值没有改变。 - user123
2
很抱歉,我不明白。如果您按下停止按钮,它会改变。如果它没有改变,您仍然会看到新的数字出现。 - Maor Refaeli
千万别叫我先生,我是靠工作谋生的 :) - Maor Refaeli
嗨,我该如何停止循环,它仍在运行。 - user123

2
你无法通过点击事件停止for循环,因为JavaScript是单线程的。循环开始。
for(let i = 1; i <= 20; i++){
...

当不被事件处理程序中断时,执行时同步运行。

它将启动20个计时器调用,每500毫秒执行一次,并在点击处理程序执行之前返回到事件循环。

您可以选择在添加元素之前无论如何启动计时器调用并检查停止标志,或者设置某种异步循环(例如使用setInterval),该循环增加i变量并在i达到最大值或发生单击事件时停止计时器回调。


2

你可以尝试不使用jQuery的下面一段代码。 我不推荐使用 $('ul').append('<li>'+ i +'</li>');, 这是一种不好的实践方式。 正确的方法是在循环之前创建节点。 在这个任务中,你可以使用setInterval而不是setTimout和循环。

let itemList = (i) => {
    let item = document.createElement('li');
    item.value = i;
    item.textContent = i;
    return item;
}

let list = document.getElementById('list');
let stopButton = document.getElementById('stop');
let i = 0,
    interval;
let reset = () => {
    clearInterval(interval)
}

stopButton.addEventListener('click', () => {
    reset()
});

interval = setInterval(() => {
    list.append(itemList(i))
    i++;
    if (i > 20) reset()
}, 300)
<button id="stop">stop</button>
<br>

<ul id="list"></ul>


你忽略了添加物品的延迟随着物品数量的增加而增加这一点。 - kevinSpaceyIsKeyserSöze

1
问题在于整个for循环已经执行完毕,甚至还没有机会按下按钮。setTimeout实际上不会休眠或阻塞,而是放置一个新事件,然后继续执行for循环。
浏览器以及所有超时目的的时钟等只有在您的代码暂时完成运行后才能运行。没有类似于sleep()函数的东西。
也许使用异步函数(ES2015 IIRC,应该由所有当前非IE浏览器支持),并等待由util.promisify(setTimeout)(2000)创建的promise可能更直观。
没有阻塞函数。代码内部没有睡眠。所有代码基本上都在CPU上运行,并设置I/O和定时器事件,这些事件在同步部分完成后异步发生。
由于这个原因,JavaScript令人难以理解。但是,一旦您看到可以通过这种方式获得一种性能,您可能会感受到异步性的价值。我的意思是...当JS代码本身正在执行时,浏览器无法检查DOM。您无法滚动,无法单击,鼠标指针本身也不会更改其类型。只有代码块完成后,浏览器才会处理所有未决事件。

1
我会以递归的方式实现这个功能。然后你需要两个中断条件:停止和计数等于最大值。

var stop = false;

var print = function(count, max) {
   setTimeout(function(){
      if(stop){
         return;
      }else if(count === max){
         return;
      }else{
         $('ul').append('<li>'+ count +'</li>');
         return print(++count, max);
      }
   }, 500);
}

$('button').click(function(){
    stop = true;
});

print(0, 20);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul></ul>

<br>
<button>stop</button>


应该只是 500 而不是 count * 500 - Maor Refaeli
@MaorRefaeli 不是很确定。 - kevinSpaceyIsKeyserSöze
在你的答案中,每个数字都会等待500毫秒乘以它的前一个数字。数字2将在数字1之后500毫秒出现,而数字11将在10之后5000毫秒出现。在问题中,每个数字都是在其前一个数字之后500毫秒出现。它仍然可以工作,但具有不同的功能。 - Maor Refaeli
1
@MaorRefaeli 你说得对,是我的错。感谢指出! - kevinSpaceyIsKeyserSöze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接