简体   繁体   English

如何停止其他代码运行,直到setTimeout()完成运行?

[英]How to stop other code from running until setTimeout() finishes running?

I am making a simple memory card game. 我正在做一个简单的记忆卡游戏。 If you click on two cards in a row that are the same they stay open. 如果您连续单击两张相同的卡片,它们将保持打开状态。 If you click on two cards in a row that are not the same they both close in 1.5s. 如果您连续单击两张不同的卡片,它们都会在1.5秒内关闭。 For that I use setTimeout(); 为此,我使用setTimeout();。 However, if during that 1.5s user clicks on any other card, event listener function starts running again while setTimeout have not finished running for the first time. 但是,如果在1.5秒内用户单击任何其他卡,则事件监听器功能将再次运行,而setTimeout尚未首次运行。 This crashes the game. 这会使游戏崩溃。 How to prevent other code from running until setTimeout finishes running for the first time? 如何防止其他代码在setTimeout第一次完成运行之前运行? Any suggestion is greatly appreciated! 任何建议,不胜感激!

const cards = document.querySelectorAll('.container__small');
let hasFlippedCard = false;
let firstCard, secondCard;
let lockBoard = false;

cards.forEach(function (card) {
  return card.addEventListener('click', flipCard);
});

function flipCard(){
  this.classList.add('flip');
  if(!hasFlippedCard){ 
    //first click
    hasFlippedCard = true;
    firstCard = this;
  }else {
    //second click
    hasFlippedCard = false;
    secondCard = this;
    setTimeout(function(){
      if(firstCard.dataset.framework !== secondCard.dataset.framework ){
        firstCard.classList.remove('flip');
        secondCard.classList.remove('flip');
      }
    }, 1500);
  }
}

You can't prevent JavaScript code to run while your setTimeout() is waiting. 在setTimeout()等待时,无法阻止JavaScript代码运行。 This is the essence of the JavaScript run-to-completion/event loop execution model. 这是JavaScript运行到完成/事件循环执行模型的本质。

In your case you should have an additional flag to not do anything during that time: 在您的情况下,您应该有一个附加标志,在此期间不做任何事情:

const cards = document.querySelectorAll('.container__small');
let hasFlippedCard = false;
let firstCard, secondCard;
let lockBoard = false;  // <<< use this flag

cards.forEach(function (card) {
  return card.addEventListener('click', flipCard);
});

function flipCard(){
  if(lockBoard) return;  // <<< check flag
  this.classList.add('flip');
  if(!hasFlippedCard){ 
    //first click
    hasFlippedCard = true;
    firstCard = this;
  }else {
    //second click
    hasFlippedCard = false;
    secondCard = this;
    lockBoard = true; // <<< set flag
    setTimeout(function(){
      if(firstCard.dataset.framework !== secondCard.dataset.framework ){
        firstCard.classList.remove('flip');
        secondCard.classList.remove('flip');
      }
      lockBoard = false;  // <<< unset flag
    }, 1500);
  }
}
function flipCard(){
  if (lockBoard) {
    return
  }
....

end in your setTimeout function 在您的setTimeout函数中结束

lockBoard = true
setTimeout(function(){
  ....
  lockBoard = false
}, 1500)

setTimeout returns a positive integer that identifies the timer created by setTimeout so if you have something like: setTimeout返回一个正整数,该整数标识由setTimeout创建的计时器,因此,如果您具有以下内容:

var myTimer = setTimeout(function(){
  console.log( 'executed' );
}, 1500);

You can use clearTimeout( timeoutId ) where timeoutId is the value of myTimer so something like clearTimeout( myTimer ) will cancel the execution of that timer if hasn't been executed. 您可以使用clearTimeout( timeoutId ) ,其中timeoutIdmyTimer的值,因此,如果clearTimeout( myTimer )尚未执行,则它将取消该计时器的执行。

So something like: 所以像这样:

var myTimer = setTimeout(function(){
  console.log( 'executed' );
}, 1500);

if ( myTimerId ) {
    clearTimeout( myTimerId );
}

The code that is inside of the if block can be placed inside of an event listener like a click as the one above so you can cancel the timer when the event has been clicked again. 可以将if块中的代码放置在事件监听器中,如上面的click一样,以便在再次单击事件时取消计时器。

Use a boolean flag to determine if the timeout is in progress and then don't execute your callback if it is true. 使用布尔值标志确定超时是否正在进行,如果超时,则不执行回调。

const cards = document.querySelectorAll('.container__small');
let cardIsFlipping = false;
let hasFlippedCard = false;
let firstCard, secondCard;
let lockBoard = false;

cards.forEach(function (card) {
  return card.addEventListener('click', flipCard);
});

function flipCard(){
  if(cardIsFlipping) {
     return;
  }

  this.classList.add('flip');
  if(!hasFlippedCard){ 
    //first click
    hasFlippedCard = true;
    firstCard = this;
  }else {
    //second click
    hasFlippedCard = false;
    secondCard = this;
    cardIsFlipping = true;
    setTimeout(function(){ 
      if(firstCard.dataset.framework !== secondCard.dataset.framework ){
        firstCard.classList.remove('flip');
        secondCard.classList.remove('flip');
      }
      cardIsFlipping = false;
    }, 1500);
  }
}

Try something like this: disable the cards before the setTimeout function and re-enable them after the function executes. 尝试如下操作:在setTimeout函数之前禁用卡,并在函数执行后重新启用它们。

document.querySelectorAll('.container__small').addAttribute("disabled",true);

setTimeout(function(){
      if(firstCard.dataset.framework !== secondCard.dataset.framework ){
        firstCard.classList.remove('flip');
        secondCard.classList.remove('flip');
      }

      document.querySelectorAll('.container__small').removeAttribute("disabled");
    }, 1500);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM