1

I'm trying to run a while loop that contains an animation. What I'd like to happen is for the while loop to pause, let the animation finish, then resume.

This is not my actual code, but it gets to the issue, I believe:

var counter = 0;

while (counter < 2) {

    $(".one").animate({"left":"+=50px"}, "slow", function() {

        counter++;

    });
};

This crashes my browser because it doesn't wait for the animation to finish (and consequently it doesn't wait for the counter to increase) before it continues through the while loop. Thanks in advance!

https://jsfiddle.net/uhmctey6/

EDIT

Thanks everyone for explaining why this is impossible. I'm still unsure how to do what I need, however, and since I didn't use my actual code for the example, I'm not sure if the suggested solutions could help.

Here is what I'm actually trying to do: I'm making a turing machine with a reader and a array of cells that it reads. Upon running this function, I'd like to search through a list of turing code lines to see if one matches the readers current state and the content of the current cell that the reader is scanning. If there's a match, I'd like for the reader to make a series of changes specified by the relevant turing code line, then visually move over to the next cell, and only after this animation has completed start the process over again by searching through the list of turing code lines to see if there is a match for the reader's new state, etc.

I understand that this can't be achieved as I have it, using a while loop, but is there a way to do something like this another way? Thanks a lot!

var run_program = function() {

    while (true) {

        for (var j=0; j< program.length; j++) {    //loops through the different lines of turingcode

            if (reader.state === program[j].state && reader.scanning === program[j].scanning) { //if there is a line of turingcode for the readers current state and scanning values.

                cellArray[reader.location].content = program[j].print; //change the content of the current cell to the new value

                reader.location += 1; //increase the value of the reader's location

                $(".reader").animate({"left":"+=50px"}, "slow"); //move the div to the right so it appears to be under the next cell

                reader.scanning = cellArray[reader.location].content; //update the readers scanning value to be the value of the new cell

                reader.state = program[j].next_state; // update the state of the reader to that specified by the line of turingcode

                break;

            }

            else if (j === $scope.program.length-1) { //if there is no line of turingcode for the readers current state and scanning values, and j has looped through the entire list of turingcode lines

                return;  //halt the function

            }

        }

    }

}
digglemister
  • 1,477
  • 3
  • 16
  • 31
  • 2
    What is it exactly that you are trying to do? Are you trying to update the counter value with every animation-step? Or do you want to run the same animation multiple times? – nils Nov 27 '15 at 19:34
  • 1
    No, it's not. The evaluation of JavaScript is bound to a single thread. The `while` loop will keep the thread busy indefinitely, preventing any other events from executing, including the `.animate()` callback. – Jonathan Lonowski Nov 27 '15 at 19:37
  • This is not my actual code, it's just a simplified example. But I suppose in this example, what I'd like to happen is for the animation to run twice, increasing the counter after each time the animation is completed. – digglemister Nov 27 '15 at 19:39

2 Answers2

3

A for-loop/while-loop can run, skip and jump - but not stand still.

In other words, you cannot run asynchronous code affectively inside a synchronous loop. See this question/answer for more on that.

In the meantime, it looks like you want to run an animation a couple of times in sequence. I believe that jQuery can queue effects like animate, so it could be as simple as chaining the two calls to animate:

$(".one")
      .animate({"left":"+=50px"}, "slow")
      .animate({"left":"+=50px"}, "slow"); /* animate twice */
.one {
  
  position: absolute;

  width: 50px;
  height: 50px;
  
  background-color: green;
  
  left: 0;
  
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="one"></div>

Update

In response to your edit, it seems like what you want to do is turn a heavily synchronous piece of code into one that can accommodate some occasionally asynchronous behaviours.

Unfortunately, your example is unworkable for me because it has no data and context. However, I've given it a stab. Below is, untested, how I would turn your code into something as you've described in the edit of your question. I hope it helps.

var run_program = function() {

  next(0);

  // read a particular iteration
  function next (j) {

    if (j < program.length) {

      // if there is a match, stop iterating and run a method which calls next when it's finished
      if (reader.state === program[j].state && reader.scanning === program[j].scanning) {

        turing(j);

      } else {

        // if there is no turing code then next is called instantly
        next(j + 1);

      }
    }
  }

  // process a line of turing code
  function turing (j) {

    cellArray[reader.location].content = program[j].print;

    reader.location += 1;

    reader.scanning = cellArray[reader.location].content;

    reader.state = program[j].next_state;

    // may as well run this last as it is asynchronous
    $(".reader").animate({"left":"+=50px"}, "slow", function () {

      // next is called when the animation is finished
      next(j + 1);

    });
  }
}
Community
  • 1
  • 1
shennan
  • 10,798
  • 5
  • 44
  • 79
1

This won't work for the reasons stated in the other answers. An alternative option is to use conditional recursion as such:

var counter = 0;

function myAnimation () {
  $(".one").animate({"left":"+=50px"}, "slow", function () {
    counter++;
    if (counter < 2) {
      myAnimation();
    }
  });
}
cmw
  • 855
  • 7
  • 17