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

好久不见. 提交于 2021-02-10 15:41:04

问题


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. For that I use 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. This crashes the game. How to prevent other code from running until setTimeout finishes running for the first time? 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);
  }
}

回答1:


You can't prevent JavaScript code to run while your setTimeout() is waiting. This is the essence of the JavaScript run-to-completion/event loop execution model.

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);
  }
}



回答2:


function flipCard(){
  if (lockBoard) {
    return
  }
....

end in your setTimeout function

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



回答3:


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);
  }
}



回答4:


Try something like this: disable the cards before the setTimeout function and re-enable them after the function executes.

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);



回答5:


setTimeout returns a positive integer that identifies the timer created by setTimeout so if you have something like:

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.

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.



来源:https://stackoverflow.com/questions/52824248/how-to-stop-other-code-from-running-until-settimeout-finishes-running

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!