0

I made a small game where there are 3 pictures of chests, and you have one attempt to choose a chest with a prize. But the problem is with the asynchronous code, a notification of defeat or victory is displayed faster than the desired picture is put in the right place, After the message, a function that puts all the chests closed that also does not allow the picture to take its place.

var count=0;
var imgArray = new Array();

imgArray[0] = new Image();
imgArray[0].src ='https://i.pinimg.com/originals/ae/f7/15/aef715f93eadcdf77c4dfa3baf5859ad.jpg'

imgArray[1] = new Image();
imgArray[1].src = "https://previews.123rf.com/images/gl0ck33/gl0ck331106/gl0ck33110600002/9781614-wooden-chest-with-gold-coins.jpg";

imgArray[2] = new Image();
imgArray[2].src = "https://i.pinimg.com/originals/94/09/6b/94096bf738837c16582902d281c520bc.jpg";


var images = document.getElementsByTagName("img");
var k = Math.floor(Math.random() * 3) + 1;
console.log("Winning number " + k);
for (var i = 0; i < images.length; i++) {
    images[i].addEventListener("click", function(e) {
        count++;
        console.log("Count " + count);
        if(this.id == k){
            count=0;
            this.src = imgArray[1].src;//here picture with a gift
            alert("You Win");// here problem,alert Faster than the picture above
            TryAgain();//And this function is faster to put pictures with closed chests
            return;
        } else { 
           this.src = imgArray[0].src;//picture empty chest
        }
   
        if (count >= 1) {
            count = 0;
            alert("You lose!!!");//alert Faster than the picture above
            TryAgain();
            return;
        }
    }, false);
}

function TryAgain(e) {
    for (var i = 0; i < images.length; i++){
        images[i].src = imgArray[2].src;//picture with close chest
        k = Math.floor(Math.random() * 3) + 1;
    }
    console.log(k);
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
    <img width="300px" height="300px"  src="https://i.pinimg.com/originals/94/09/6b/94096bf738837c16582902d281c520bc.jpg" id="1">
    <img width="300px" height="300px"  src="https://i.pinimg.com/originals/94/09/6b/94096bf738837c16582902d281c520bc.jpg" id="2">
    <img width="300px" height="300px"  src="https://i.pinimg.com/originals/94/09/6b/94096bf738837c16582902d281c520bc.jpg" id="3">
    <button id="btn" onclick="TryAgain()">Try Again</button>
</body>
</html>

1
  • @basic But why is the notification displayed earlier than the picture? When I select the picture, this happens alert("You Win"); then this.src=imgArray[1].src; but not this this.src=imgArray[1].src; alert("You Win"); Commented Oct 11, 2019 at 19:49

2 Answers 2

1

Answer:

You need to wait for the images to get done loading before running alert.

alert completely halts the processing of code. Therefore if the image isn't loaded before it is executed you're not going to see the change occur.

A simple pattern to do this would be:

  let self = this;
  this.src = imgArray[1].src;
  this.onload = function() {
        alert("You Win");
        self.onload = undefined;
        TryAgain();
  }
  return;

Example:

var count=0;
var imgArray = new Array();

imgArray[0] = new Image();
imgArray[0].src ='https://i.pinimg.com/originals/ae/f7/15/aef715f93eadcdf77c4dfa3baf5859ad.jpg'

imgArray[1] = new Image();
imgArray[1].src = "https://previews.123rf.com/images/gl0ck33/gl0ck331106/gl0ck33110600002/9781614-wooden-chest-with-gold-coins.jpg";

imgArray[2] = new Image();
imgArray[2].src = "https://i.pinimg.com/originals/94/09/6b/94096bf738837c16582902d281c520bc.jpg";


var images = document.getElementsByTagName("img");
var k = Math.floor(Math.random() * 3) + 1;
console.log("Winning number " + k);
for (var i = 0; i < images.length; i++) {
    images[i].addEventListener("click", function(e) {
    let self = this;
        count++;
        console.log("Count " + count);
        if(this.id == k){
            count=0;
            this.src = imgArray[1].src;//here picture with a gift
            this.onload = function() {
            alert("You Win");// here problem,alert Faster than the picture above
            self.onload = undefined;
            TryAgain();//And this function is faster to put pictures with closed chests
            }
            return;
        } else { 
           this.src = imgArray[0].src;//picture empty chest
            this.onload = function() {
            alert("You Lose");// here problem,alert Faster than the picture above
            self.onload = undefined;
            TryAgain();//And this function is faster to put pictures with closed chests
            }
            return;
        }
   

    }, false);
}

function TryAgain(e) {
    for (var i = 0; i < images.length; i++){
        images[i].src = imgArray[2].src;//picture with close chest
        k = Math.floor(Math.random() * 3) + 1;
    }
    console.log(k);
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
    <img width="300px" height="300px"  src="https://i.pinimg.com/originals/94/09/6b/94096bf738837c16582902d281c520bc.jpg" id="1">
    <img width="300px" height="300px"  src="https://i.pinimg.com/originals/94/09/6b/94096bf738837c16582902d281c520bc.jpg" id="2">
    <img width="300px" height="300px"  src="https://i.pinimg.com/originals/94/09/6b/94096bf738837c16582902d281c520bc.jpg" id="3">
    <button id="btn" onclick="TryAgain()">Try Again</button>
</body>
</html>

Sign up to request clarification or add additional context in comments.

2 Comments

What do you think about this solution? setTimeout(function() { alert("You Win"); TryAgain(); }, 100); By the way, it works
@YuraKhomitsky That's fine. This code could be refactored to be better as well, but I'm under the assumption that this is kind of "toy code". For instance, I wouldn't advocate using onload in this way in any kind of prod environment, but for learning/fun it's fine.
1

Images do not appear as soon as you set this.src

They appear when the browser is ready to show them, which may take some time. Perhaps you can use the "load" event listener? This will fire once the image is visible. At that stage you can do the alert?

images[i].addEventListener("load", function(e) { 
  // This will run only once the image is loaded (i.e. visible)
} )

7 Comments

What do you think about this solution? setTimeout(function() { alert("You Win"); TryAgain(); }, 100); By the way, it works
It's an idea, but I don't like it because it hard-codes a 100-ms delay. What if the internet is slower? Better to do it on the "load" event, so you can be sure it doesn't occur too early, without having to set a ridiculously long delay just to be sure.
It is good practice not to put in arbitrary delays to solve seemingly small problems in asynchronous programming. The reason is that it may work nicely now, but may not work in future. By that time the relevant programmer (who may be, unfortunately, you still!) will have great difficulty in working out what is going wrong. Use the "load" 8-)
What do I need to write in the load function? src pictures?
@zfrish's answer has an excellent suggestion. alert("You Win"); self.onload = undefined; TryAgain();
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.