【问题标题】:For Loop SetTimeout Works Only 1 TimeFor Loop SetTimeout 仅工作 1 次
【发布时间】:2019-10-14 13:59:37
【问题描述】:

我在下面有一个带有点击功能的按钮。它有 3 个嵌套的 for 循环和 1 个 setTimeout 函数。

以下循环循环了 5 次。我希望下面的代码可以工作(5x5)总共 25 秒的执行时间,并且每 5 秒的控制台输出应该被“等待”打印。

但是下面的代码只工作 5 秒,并立即打印“5 hello”。在不改变我的 for 循环结构的情况下,我怎样才能让它按我的意愿工作?

  jQuery("#btn_trendyolStocksSYNC").click(function() {
    for(var product in all){
      var colors = all[product];
      for(var singleColor in colors[0]){
        var size = colors[0][singleColor];
        for(var index in size){
          var singleSize = size[index];
          setTimeout(function (){
            console.log('Waited');
          }, 5000);
        }
      }
    }
  });

编辑:我不使用带索引的 for 循环,因此数字索引 for 循环的解决方案对我不起作用。

【问题讨论】:

  • 您的所有计时器实际上都是立即设置并同时执行的。您可能会使用await 和Promise,或者使用嵌套函数来调用定时器的下一次迭代。
  • @Ivar for 循环类型不相似。我也看到了这个问题,但没有帮助

标签: javascript asynchronous settimeout


【解决方案1】:

您可以尝试添加await 和Promise:

jQuery("#btn_trendyolStocksSYNC").click(async function() {
    for(var product in all){
      var colors = all[product];
      for(var singleColor in colors[0]){
        var size = colors[0][singleColor];
        for(var index in size){
          var singleSize = size[index];
          await new Promise(resolve => setTimeout(function (){
            console.log('Waited');
            resolve();
          }, 5000));
        }
      }
    }
});

这只是告诉你的循环停止并且只有在 Promise 对象调用它的resolve 参数函数时才继续。这样你的延迟应该只是在下一次迭代之前发生。这是重要的代码:

await new Promise(resolve => setTimeout(function (){
      console.log('Waited');
      resolve();
}, 5000));

它只是创建一个Promise,我们将在超时时间超过 5000 毫秒后解决它。然后我们告诉我们的循环在继续下一项之前简单地等待完成。

注意您还需要将async 添加到您的处理程序函数中,以便javascript 知道该函数可以等待并根据需要等待。

【讨论】:

  • 我收到此错误:未捕获的语法错误:等待仅在异步函数中有效
  • 啊,是的,我的错,只需在您的处理函数之前添加async(我已将答案修改为jQuery("#btn_trendyolStocksSYNC").click(async function() {...)这是告诉javascript这个函数将包含一些等待的必要条件。
  • Uncaught SyntaxError: missing ) 在参数列表之后,它在调试器中显示 -> console.log('Waited')。
  • 抱歉,我无法在本地测试您的代码,这又是我的错 - Promise 设置中的 } 太多了。修改了我的答案。
  • 我查看了您之前的问题,由于您使用的是jQuery.trigger,因此这里无法异步等待。您最好创建一个可以直接调用自己的通用async function,并传入一个具有函数体所需值的对象。这样,您可以使用相同的函数在jQuery.on 中注册,并且可以重用代码,同时允许在 for 循环中等待。它虽然有点复杂。请记住,jQuery 是在 async/await 出现之前构建的 waaaaaay...
【解决方案2】:

setTimeout(); 函数是异步的,这意味着您的脚本不会等待它完成就继续。这就是它有回调的原因。

试试这样的:(不是最好的方法)

//delayed loop
var i = 1;
function loop() {
    //wait 5 secs
    setTimeout(function() {
        console.log(i);
        if(i>5) {
            //cancel
            return;
        }
        loop();
        i++;
        return;
    }, 1000);
    if(i>5) {
        //cancel function
        return;
    }
}
//do the loop
loop();

就像这里所说的那样,您可以将setTimeout 放在if 语句中。

当然要在循环结束后做一些事情,你需要一个回调函数。

【讨论】:

  • 如果您在不同的位置进行检查,您可以大大简化此操作。又名if( i < 5 ) setTimeout(...),而不是之后检查。您甚至可以在此处增加 i 以保存另一行代码 if( i++ < 5 ) ... - 但本质上,这确实是在没有更新的 async/await 的情况下处理它的方法。它确实需要在 OP 端进行大量重构。
【解决方案3】:

您可以使用 setInterval 和 clearInterval。

var n=0;
var a = setInterval(()=>{
    console.log("Waited");
    n++; if(n==5){clearInterval(a);}
},5000);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-11
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 2019-01-01
    相关资源
    最近更新 更多