构建一个simon游戏,并且在另一个函数运行之前无法完成一个功能

时间:2017-11-21 02:51:55

标签: javascript jquery

在我的correctClick函数中,我将按钮单击与数组(buttonPressValidate)进行比较,该数组包含屏幕上突出显示的所有按钮ID。如果单击突出显示的按钮,则replayFlash函数会突出显示buttonPressValidate中的所有按钮,然后highLightSquare函数应该在replayFlash函数完成后亮起一个新的正方形。我遇到的问题是我的highLightSquare函数在突出显示新方块之前没有等待replayFlash函数完成。

    var clickNum = 0;
function correctClick(buttons) {
      $(".button").on("click", function() {
        var thisClick = $(this).attr("id");
        var matchBut = buttonPressValidate[clickNum];
        if(thisClick == matchBut) {
          clickNum++;
          setTimeout(function() {
            replayFlash(buttonPress);
            if(buttonPressValidate.length === clickNum) {
               setTimeout(function() {
                 highLightSquare(simonButtons);
               }, 1500);
            }
          }, 1500);
        }  
      });  
}

function replayFlash(butPressArr) {
      function eachColor(i) {
        var litColor = $(butPressArr[i]);
        setTimeout(function() {
          litColor.addClass("lit");
          if(litColor.attr("id") === "greenButton") {
             greenButton.play();
          } else if(litColor.attr("id") === "redButton") {
              redButton.play();        
          } else if(litColor.attr("id") === "blueButton") {
              blueButton.play();      
          } else if(litColor.attr("id") === "yellowButton") {
              yellowButton.play();      
          }
          setTimeout(function() {
            litColor.removeClass("lit");
          }, 1000 - (1000 / 3));
        }, 1000 * (i + 1));
      }
      for(var i = 0; i < butPressArr.length; i++) {
        eachColor(i);
      }
}

1 个答案:

答案 0 :(得分:0)

setTimeout的优点在于它是非阻塞的(即异步),所以你的应用程序可以做其他事情,直到计时器熄灭。

除非在时间到期之前不希望执行继续执行,否则有时会出现setTimeout问题。您的replayFlash函数在播放序列之前返回,因为setTimeout不会阻止。代码的执行将一直持续到setTimeout间隔结束为止。

您需要一个同步/阻止计时器。一个例子是already on SO (click here to view)。下面我重写了你的replayFlash函数(未经测试)以使用这个阻塞等待模式。希望这会指出你正确的方向。您还需要以类似的方式修改您的correctClick函数。

// from @thinkbonobo's answer here:
// https://stackoverflow.com/questions/6921895/synchronous-delay-in-code-execution

function wait(ms) {
    var start = Date.now(),
        now = start;
    while (now - start < ms) {
      now = Date.now();
    }
}

function replayFlash(butPressArr) {
  function eachColor(i) {
    var litColor = $(butPressArr[i]);
    wait(1000 * (i + 1));
    litColor.addClass("lit");
    if(litColor.attr("id") === "greenButton") {
       greenButton.play();
    } else if(litColor.attr("id") === "redButton") {
        redButton.play();        
    } else if(litColor.attr("id") === "blueButton") {
        blueButton.play();      
    } else if(litColor.attr("id") === "yellowButton") {
        yellowButton.play();      
    }
    wait(1000 - (1000/3));
    litColor.removeClass("lit");
  }
  for(var i = 0; i < butPressArr.length; i++) {
    eachColor(i);
  }
}

修改

受到上述用户Roamer-8888评论的启发,我想提出另一个选择:承诺。这实际上是IMO的“正确”答案,但它是一个更先进的概念。通过“等待”,Promise可让您控制异步环境中代码的执行,直到“履行”或“已解决”未来操作的承诺。

现在许多浏览器本身都支持promises,但有些浏览器需要一个库,所以让我们看一下流行的“Q”promise库的例子。这是一个简单的例子,说明如何使用promise等到setTimeout超时,然后继续执行其他操作。请注意,Q库(来自q.min.js)创建了用于创建promise的全局变量Q.

<script src='//cdnjs.cloudflare.com/ajax/libs/q.js/0.9.2/q.min.js'></script>
<script>
function myPatientFunction(message) {
  var deferred = Q.defer();
  setTimeout(function() {
    console.log(message);
    deferred.resolve();
  }, 1000)
  return deferred.promise;  
}


myPatientFunction("Hello world")
.then(function() {
  console.log("See? I waited my turn")
})
</script>

或者,使用most browsers support

的原生承诺
<script>
function myPatientFunction(message) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      console.log(message);
      resolve();
    }, 1000)
  });  
}


myPatientFunction("Hello world")
.then(function() {
  console.log("See? I waited my turn")
})
</script>