【问题标题】:setTimeout in a loop with 3 functions to be executed after the previous one completedsetTimeout 在一个循环中,有 3 个函数在前一个函数完成后执行
【发布时间】:2014-11-06 19:28:33
【问题描述】:

I 3 个函数 a()、b() 和 c() 将在循环中执行 x 次,如下所示: 我必须调用函数 a(); a() 完成后,我必须等待 s1 秒才能调用函数 b();经过 s1 秒后,我必须调用函数 b(); b() 完成后,我必须等待 s2 秒才能重新开始循环。

for(var i=0; i<x; i++) {
a();
setTimeout(b,s1);
setTimeout(function() {},s2);
}

但是,上述循环函数 a() 和 b() 无法正确执行。无论之前的功能是否完成,它们都会执行。

我也尝试过:

var FunctionOne = function () {
// create a deferred object
var r = $.Deferred();

// do whatever you want (e.g. ajax/animations other asyc tasks)
a();

setTimeout(function () {
    // and call `resolve` on the deferred object, once you're done
    r.resolve();
}, s1);

// return the deferred object
return r;
};

var FunctionTwo = function () {
    b();
};

for(var i=0; i<x; i++) {
setTimeout(FunctionOne().done(FunctionTwo),s2);
}

但它没有按预期工作。

你能帮帮我吗?


编辑


函数a()和b()如下:

function a() {
$.ajax({
        type: $('#form1').attr('method'),
        url: 'Misura',
        data: $('#form1').serialize(),
        beforeSend: function() {
            if($.trim($('#nomeMisura').val()) == "") {
                alert('<%= labels.getString("nomeMisuraObbligatorio") %>');
            $('#nomeMisura').val("");
            return false;
        }
    },
    success: function (data) {
        $('#misura').attr('disabled', true);
        $('#pulisci').attr('disabled', false);

        misurazioneInCorso = true;
    }
});

}

function b() {
$.ajax({
    type: $('#form1').attr('method'),
    url: 'Pulisci',
    data: $('#form1').serialize(),
    success: function (data) {
        var numeroCampioniMisurazione = Number(data.delta.campione2) - Number(data.delta.campione);
        //visualizzo in tabella le misurazioni
        $('#tabellaMisurazioni').append('<tr id="Misurazione"><td>'+data.nomeSessione+'</td><td>'+data.nome+'</td><td>'+data.delta.campione+'</td><td>'+data.delta.campione2+'</td><td>'+numeroCampioniMisurazione+'</td><td>'+data.delta.f1+'</td><td>'+data.delta.f2+'</td><td>'+data.delta.f3+'</td><td>'+data.delta.f4+'</td><td>'+data.delta.f5+'</td><td>'+data.delta.f6+'</td><td>'+data.delta.f7+'</td><td>'+data.delta.f8+'</td><td>'+data.delta.f9+'</td><td>'+data.delta.f10+'</td><td>'+data.delta.f11+'</td><td>'+data.delta.f12+'</td><td>'+data.delta.t1+'</td><td>'+data.delta.t2+'</td><td>'+data.delta.to+'</td><td>'+data.delta.ft+'</td><td>'+data.delta.rh+'</td></tr>');
        $('#tabellaMisurazioni tbody tr:first').html('<td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td>');

        $('#misura').attr('disabled', false);
        $('#pulisci').attr('disabled', true);
        $('#esportaCsvMisurazioni').attr('disabled', false);
        $('#nomeMisura').val('');

        misurazioneInCorso = false;
    }
});

}

所以,我认为 a() 和 b() 是异步函数。

【问题讨论】:

  • 第二种方法中什么不符合预期? a 是同步的还是异步的?

标签: javascript jquery loops settimeout deferred


【解决方案1】:

我提出的代码与 Kevin Nelson 的代码非常相似。在我的代码中,“控制逻辑”没有“包含”在应用程序功能中。

您可以在以下链接中找到我的“解决方案”的 PDF 版本——它包括一个“分析”,代码可以在末尾找到——在以下链接中:http://www.aespen.ca/AEnswers/1415708506.pdf

以下内容是从 PDF 文档生成的。

【讨论】:

  • 我不确定这个解决方案能否如我所愿,因为 a() 和 b() 函数包含异步 AJAX 调用。例如,在您的函数 PL1() 中,我需要 a() 在调用 setTimeout(PL2,s1) 之前完成其所有任务。
  • 我不知道为什么,但您的解决方案似乎有效 :) 非常感谢!
【解决方案2】:

您可以实现某种调度程序:下面我使用一个最简单的堆栈,其中包含一个函数或在下一个任务执行之前等待的时间。
下面的代码未经测试,但可能会给你一些想法:

var tasks =  [];         // list of all tasks / wait time
var currTaskIndex = 0;  
var looping = true;

function runTask() {
   if (currTaskIndex==-1) return;
   var currTask = tasks[currTaskIndex];
   // iterate
   currTaskIndex++;
   if (currTaskIndex==tasks.length) {
        if(looping ) {
           currTaskIndex=0;
         } else {
           currTaskIndex=-1;               
         }
   }
   // run task / wait
   if (typeof currTask == "function") {
      currTask.call(null);
      runTask();
   } else {
     // currTask is a time -> wait
     setTimeout(runTask, currTask);
   }
}

搭配使用

tasks.push(a);
tasks.push(s1);
tasks.push(b);
tasks.push(s2);

runTask();

【讨论】:

    【解决方案3】:
    var x=5;
    outerFun(){
        if(x){
            a();
            setimeout(function(){
                b();
                setTimeout(function(){
                    //do its part
                    x--;
                    outerFun();
                },s2);      
            },s1);
        }
    }
    

    【讨论】:

      【解决方案4】:

      对于Asyncrhonous调用,你总是需要将“下一步”(取决于异步活动的结果)放入异步活动结束时调用的回调方法中。

      根据您的 cmets,您的方法包含异步 ajax 调用。您的 setTimeout 调用也是异步的。如果你打电话:

      setTimeout(b,s1);
      setTimeout(c,s2);
      

      那么两个超时将同时运行。这意味着您正在进入“回调地狱”的世界……这并不像某些人想象的那么难,恕我直言,但这是一种不同的思维方式。

      为了防止后续方法执行并防止循环进入下一次迭代并立即执行整个循环,您需要在 a 的末尾调用 b 并在 b 的末尾调用 c。在开始下一次迭代之前,您还必须等待 c 结束,这意味着在 c 完成后循环,而不是将 c 放入循环中......否则,您的循环将立即压缩所有 x 迭代并且您将几乎同时运行所有方法(考虑到我之前提到的假设,a() 除外,因为它是同步调用)。所以,你需要做的是:

      var i = 0;
      var x = 100;
      
      function a() {
          //end our loop inside the method
          if( i++ < x ) {
              //shortening your ajax call to just success method
              var ajaxSuccess = function (data) {
                  $('#misura').attr('disabled', true);
                  $('#pulisci').attr('disabled', false);
      
                  misurazioneInCorso = true;
      
                  setTimeout(b,s1);
              }
          }
      }
      function b() {
          //shortening your ajax call to just success method
          var ajaxSuccess = function (data) {
              var numeroCampioniMisurazione = Number(data.delta.campione2) - Number(data.delta.campione);
              //visualizzo in tabella le misurazioni
              $('#tabellaMisurazioni').append('<tr id="Misurazione"><td>'+data.nomeSessione+'</td><td>'+data.nome+'</td><td>'+data.delta.campione+'</td><td>'+data.delta.campione2+'</td><td>'+numeroCampioniMisurazione+'</td><td>'+data.delta.f1+'</td><td>'+data.delta.f2+'</td><td>'+data.delta.f3+'</td><td>'+data.delta.f4+'</td><td>'+data.delta.f5+'</td><td>'+data.delta.f6+'</td><td>'+data.delta.f7+'</td><td>'+data.delta.f8+'</td><td>'+data.delta.f9+'</td><td>'+data.delta.f10+'</td><td>'+data.delta.f11+'</td><td>'+data.delta.f12+'</td><td>'+data.delta.t1+'</td><td>'+data.delta.t2+'</td><td>'+data.delta.to+'</td><td>'+data.delta.ft+'</td><td>'+data.delta.rh+'</td></tr>');
              $('#tabellaMisurazioni tbody tr:first').html('<td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td><td>---</td>');
      
              $('#misura').attr('disabled', false);
              $('#pulisci').attr('disabled', true);
              $('#esportaCsvMisurazioni').attr('disabled', false);
              $('#nomeMisura').val('');
      
              misurazioneInCorso = false;
      
              setTimeout(c,s2);
          }
      }
      function c() {
          //do your stuff, then loop back to a
          a();
      }
      
      a();
      

      注意,我正在做的唯一一件事就是将您的“下一个调用”放入 AJAX 调用的成功方法中,并且我通过让 c() 调用 a() 而不是将其放入 @987654326 来循环@ 环形。然后,我修改了a(),使其在x 迭代后结束循环,而不是在我放置在那里的if() 内执行。这将确保它们按顺序进行。

      【讨论】:

      • 我用 a() 和 b() 函数编辑了我的第一篇文章。它们似乎是异步函数($.ajax 调用)。我还没有时间尝试任何建议的解决方案。不知道哪一个适合异步函数。
      • 更新为使用来自 ajax 调用的回调。
      猜你喜欢
      • 2011-05-14
      • 2015-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-15
      • 1970-01-01
      • 2013-11-09
      相关资源
      最近更新 更多