【问题标题】:Javascript: How to ensure sequential execution with multiple nested loops using setTimeout delays?Javascript:如何使用 setTimeout 延迟确保多个嵌套循环的顺序执行?
【发布时间】:2014-02-08 15:36:21
【问题描述】:

我一直在查找许多关于 setTimeout() 和循环延迟的 SO 帖子,但一直未能找到可行的解决方案。我正在浏览器中对某些数据进行动画演示,我需要多次重绘相同的序列,事件以特定顺序发生,包括带有延迟的内部循环。像这样:

for (var pass = 1; pass <= passes; pass++) {

    // 1. Prep some data, update DOM (must happen *before* inner loop)

    // 2. Run inner loop with delays (multiple DOM updates...)
    (function loopWithDelay() {
        setTimeout(function() {
            // Iterate on data
            // Update DOM on each iteration
            if ( !condition() ) { 
                loopWithDelay(); 
            }
        }, 250);   // delay at each iteration
    })(); 

    // 3. Do wrap-up calcs, update DOM (must happen *after* above loop)

}   // If more passes remain, repeat..

因此,我能够延迟内部循环的迭代(第 2 部分),但是由于它是非阻塞的,因此第 3 部分会立即执行,因此父循环无法正常工作。我有点理解 Javascript 的异步/非阻塞性质,但无法完全理解如何干净利落地执行这样的多序列(或者实际上让它工作!)希望对这种特殊情况提出一些建议。

【问题讨论】:

    标签: javascript settimeout


    【解决方案1】:

    这样做(我称之为callbacl循环):

    function outerloop(pass, passes) {
        if (pass > passes) return;
        // 1. Prep some data, update DOM (must happen *before* inner loop)
    
        // 2. Run inner loop with delays (multiple DOM updates...)
        (function loopWithDelay() {
            setTimeout(function () {
                // Iterate on data
                // Update DOM on each iteration
                if (!condition()) {
                    loopWithDelay();
                } else {
                    outerloop(pass++, passes);
                }
            }, 250); // delay at each iteration
        })();
    
        // 3. Do wrap-up calcs, update DOM (must happen *after* above loop)
    
    }
    outerloop(1, passes);
    

    【讨论】:

      【解决方案2】:

      如果您想使用异步方法,您的设计需要更改为 event-driven 而不是结构化的。

      基本上,您需要使用callbacks 来处理延迟(或者如果您想成为最前沿的Promises :D)

      我在想这样的事情:

      (function() {
        var after_loop = function() {
          // Move 3 here
          // 3. Do wrap-up calcs, update DOM (must happen *after* above loop)
        }
      
        var loopWithDelay = function() {
          // update whatever DOM you want
          updateDom();
      
          // Check if we need to stop the looping
          if (stop_condition) {
            clearInterval(interval);
            after_loop();
          }
        }
      
        var interval = setInterval(loopWithDelay, 250);
      })();
      

      loopWithDelay 会每 250 毫秒调用一次,当stop_condition 为真时,它会停止运行并运行after_loop();

      【讨论】:

      • 谢谢!我想我明白了,会试一试的。我仍然需要确保任务的第 1 部分得到执行在开始间隔之前(我是否只需将该代码放在这个自执行功能块之前?),以及如何重复所有这些多次(保持顺序..)
      • 我接受了 Mehran 的回答,但是,我也能够调整您的方法:我命名了父匿名函数,添加了 pass 的 arg,并将其自动执行为 (function() {...})(passes); 我递减passafterLoop() 内,如果仍有通过,请再次调用父级。我还添加了一个新的beforeLoop() 函数,它在第一次由间隔调用loopWithDelay() 时运行(使用标志来清除/设置)。 Mehran 的解决方案对我来说感觉更干净,但两者都有效,我感谢您对事件驱动编程的解释!
      【解决方案3】:

      可能是这样的……?

      var states = {
       beforeLoop: 0,
       innerLoop: 0,
       afterLoop: 0
      };
      var timeouts = {
       beforeLoop1: undefined,
       beforeLoop2: undefined,
       innerLoop1: undefined,
       innerLoop2: undefined,
       afterLoop1: undefined,
       afterLoop2: undefined
      }
      function setTimeoutType(fun,time,type){
       states[type]++;
       return setTimeout(fun,time);
      }
      function mainLoop(){
       if(beforeLoop1 == undefined)
        beforeLoop1 = setTimeoutType(beforeFun1,1000,'beforeLoop'); 
       if(beforeLoop2 == undefined)
        beforeLoop2 = setTimeoutType(beforeFun2,1000,'beforeLoop'); 
       if(states.beforeLoop == 0){
        if(innerLoop1 == undefined)
         innerLoop1 = setTimeoutType(innerFun1,1000,'innerLoop'); 
        if(innerLoop2 == undefined)
         innerLoop2 = setTimeoutType(innerFun2,1000,'innerLoop'); 
        if(states.innerLoop == 0){
         if(afterLoop1 == undefined)
          afterLoop1 = setTimeoutType(afterFun1,1000,'afterLoop'); 
         if(afterLoop2 == undefined)
          afterLoop2 = setTimeoutType(afterFun2,1000,'afterLoop'); 
         if(states.afterLoop == 0){
          // loops done
         }
         else setTimeout(mainLoop,1000);
        }
        else setTimeout(mainLoop,1000);
       }
       else setTimeout(mainLoop,1000);
      }
      function beforeFun1(){
       // code
       states.beforeLoop--;
      }
      function beforeFun2(){
       // code
       states.beforeLoop--;
      }
      function innerFun1(){
       // code
       states.innerLoop--;
      }
      function innerFun2(){
       // code
       states.innerLoop--;
      }
      function afterFun1(){
       // code
       states.afterLoop--;
      }
      function afterFun2(){
       // code
       states.afterLoop--;
      }
      function startThisHugeThing(){
       timeouts = {
        beforeLoop1: undefined,
        beforeLoop2: undefined,
        innerLoop1: undefined,
        innerLoop2: undefined,
        afterLoop1: undefined,
        afterLoop2: undefined
       }
       setTimeout(mainLoop,1000);
      }
      

      【讨论】:

        猜你喜欢
        • 2019-04-14
        • 1970-01-01
        • 2015-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多