Page 9: Animation Loops
Spring 2026 Sample Solution
On this page, we continue our exploration of event-based programming in the web browser. For graphics, this will be particularly important since it is how we will create animation (making things move). But for now, we aren’t doing graphics, so we’ll use simpler examples to learn. The important concept isn’t what we’re animating: it is how we are doing animation within the event-based paradigm. We’ll animate more interesting things later (even in this workbook).
On the last page, we saw how we program the browser in an event-based fashion. Our programs are run in response to “events” that happens. Even the initial code is running in response to the page being loaded.
A simplified version: the browser doesn’t do anything in parallel. It runs an event loop where it gets the next event from the queue of things to do, runs the program associated with that event, which returns control to the event loop (that gets the next event from the queue, and so on).
But there is a second part of this event model: the web browser need to be responsive in case other events happen. Because there is no parallelism, the browser cannot respond to events while it is running the program to respond to some other event. If a program takes a long time, the browser won’t be able to respond to other events.
Here is a simple example. When the user presses the button, the program waits for five seconds before signalling the user. Notice how the entire page freezes. When you move the cursor out of the button, the button doesn’t change back to the “unhovered state.” This is obviously bad. The handleblock function is attached to the button, and the text next to the button is the blocktest span.
|
|
Also… notice that you never see the “Waiting” line. Because our program has control, the web browser can’t process changes to the page. So while our program is busy looping, the changes we made to the web page are not visible to the user. The user only sees the changes when our program returns control to the browser. But in this case, we change the contents of the web page before the user ever sees it.
Time in event-based programming
In event based programming, our programs cannot keep control for a long period of time. Instead, we need to break the work into small pieces. After each event, the program does a small amount of work and returns control to the web browser.
But, what if the program needs to do more work than it can do in a short amount of time? It can schedule an event - put something into the browser’s queue that will cause the program to be called again in the future. There are various mechanisms in JavaScript for doing this. For now, we’ll focus on using callbacks.
A simple callback is a timer. A timer sets an “alarm” that goes off some amount of time in the future and then calls a function. To re-write our program that responds to a button after the delay, we still have a function that responds to the click event of the button. However, this program doesn’t spend five seconds waiting around. Instead, it sets a timer to have another function called after two seconds.
|
|
Notice how I defined a function on line 5 to be executed when the timer goes off. This is an “anonymous” function - I didn’t give it a name. I could have written it as:
1let count2=0;
2function handletimer() {
3 count2++;
4 timertest.innerHTML = "Waiting...";
5 function handleTimer() {}
6 timertest.innerHTML = `button pushed ${count2} times`;
7 }
8 setTimeout(handleTimer, 2000);
9}The important thing: we didn’t do a long running computation. Our program quickly returned control to the event loop. We scheduled “more work” for the future. This meant that the browser was able to show the “Waiting…” message, and that other events could be processed.
Of course, this also means that the browser could have another click event during the waiting period, so we might want to have our program handle that case…
|
|
Animation: As soon as possible
If we want to make a stream of changes (for example, in order to make something move across the screen), we repeatedly set a timer and each time move things forward a little bit. The function effectively calls itself - or schedules itself to be called again in the future.
|
|
This code, while short is important to understand - since it is the way we will make “animation loops”. The key line is 4 - notice how the function schedules itself to be called again “as soon as possible” in the future (with a delay of zero). This is similar to (but not exactly the same as) recursion: the function does cause itself to get called again. However, it returns control to the event loop. The event loop can process other events in the queue first. Line 111 puts an event in the queue that will cause the function to be called in the future.
Line 6 is important. Lines 1-5 define a function, which effectively implements an infinite loop by scheduling itself to be called. But we need to call the function the first time, on line 6, to start the loop.
There is also a small JavaScript annoyance to notice on line 2. The value of the slider is actually a string, not a number. JavaScript’s aggressive coercion rules would cause “1”+1 to be “11”, not 2. We need to explicitly need to convert to a number for addition (on line 2). On line 3, Javascript is smart enough to know to convert back to a string.
But the important point: in event based programming, we do big (or at least time consuming) things (like make a slider move continuously over time) by breaking it up into small pieces. Rather than writing loops, we have functions that schedule themselves to be called again in the future..
The animation “loop” isn’t written as a loop.
Not as fast as possible…
In the previous example, we have a delay of zero: we scheduled the event for “as soon as possible.” The new event (to call back) is placed on the queue immediately. If there isn’t much work in the browser’s event queue, things will return quickly.
However, for doing graphics, we don’t need to do things that fast. As we discussed on Page 8 (Displays and Frame Rate), the display only updates a fixed number of times per second. We don’t need to make an extra drawing that the user will never see. Rather than scheduling our next drawing event for “as soon as possible” we can schedule it for “after the next screen update.” Because of the way buffering works, this is the only way we can be sure the user sees the things that have already been drawn.
The web browser implements this in a function called requestAnimationFrame. This function is very similar to setTimeout, except that rather than waiting a fixed amount of time before putting an event into the queue, it waits until after the next screen refresh (or at least until the buffer is written to to be sent to the screen). To read about the details of requestAnimationFrame see the Official RequestAnimationFrame Docs. We’ll discuss the connection between the buffering concepts on Page 8 (Displays and Frame Rate) later.
The code is very similar, but there will be a difference:
|
|
|
|
Depending on your computer, you will see the sliders moving at different rates. On the left, the slider is moving “as fast as possible” - which means it might move multiple times between each screen refresh - there are changes that you won’t see. On the right, we use requestAnimationFrame so you will see every step. On my computer, this is slower.
Also, the rate at which the right slider (requestAnimationFrame) moves depends on the frame rate of the display. As I mentioned on Displays and Frame Rate, my computer has 2 different displays: one that is 60fps and one that is 120fps. I have no idea how fast it moves on your computer.
This simple example illustrates two important points when doing web graphics:
- We need to use
requestAnimationFrameso that we don’t draw “too fast” - If we care about how fast things move on screen, we need to measure actual time.
We’ll do this a lot when we start actually writing graphics programs, so we’ll explore it a bit now. The examples will be simple (like the sliders), but make sure you understand how it works.
A Toy Example
This box has a simple example of RequestAnimationFrame.
view - look at the box and experiment with it
examine - look at the code for the box
edit - change the box's content
rubric - several steps are suggested in the rubric page - form elements on page in rubric
01-09-01.html 01-09-01.js
If you read the code (and you should) you’ll see that when the button is clicked, the first line is changed and a timer is set to call the function future1 in the future. When future1 is called, it changes line 2, and schedules an event to call future2 in the future. And this repeats a 3rd time.
Parallelism
Let’s return to the slider example. Here I will extend it to make multiple sliders move at once.
view - look at the box and experiment with it
examine - look at the code for the box
edit - change the box's content
rubric - several steps are suggested in the rubric page - form elements on page in rubric
01-09-02.html
Of course, we could put the sliders all in the loop from the previous box. But, let’s pretend each slider was some more complicated thing, so we wanted to keep the code separate and independent. In the ideal world, we could have the code for each slider run in parallel. However, in the web browser, we have to use the event-driven loop model. Each independent loop does a small bit of work, and schedules itself to run again.
Make sure you are understanding what is happening in 01-09-02.html. Including the way that I used separate modules (even though they are in the same file), so I could re-use the function names.
This “psuedo-parallelism” is really a key aspect of browser based programming: we write our code to do work in small chunks, and when it does, it “returns” to the browser main loop. That way the “browser main loop” can make sure that all of the different things can run in “parallel” - even though the really are not really running in parallel, they are taking turns. (Geeky point: at least in the old days, each web page was really a single thread. Modern web browsers might actually parallelize things in some cases.)
Programming Practice
This is a good opportunity to discuss some programming concepts. Event programming means we write little functions to do things (since each little function does a little bit).
Here is a re-write of the previous example. Except that rather than write 3 functions, we’ll write a loop that creates the three functions we need. This example has two sets of sliders: one that is written correctly (the top one), and a second version of the code that has a bug in it (the lower set of three sliders). You need to fix the bug.
view - look at the box and experiment with it
examine - look at the code for the box
edit - change the box's content
rubric - several steps are suggested in the rubric page - form elements on page in rubric
01-09-03.html
| Kind
Kind of rubric items: standard - expected from all students advanced - used to get a better grade creative - an opportunity to do something creative levels - rubric item graded by selected achievement level optional - not required, but encouraged |
Description | |
| standard | Fix bug so that all the sliders work |
Read the code for 01-09-03.html.
This code uses closures which are an important programming concept. They are, admittedly, tricky. If you have never seen closures before, it will take some practice before you understand them. However, once you do understand them, they are extremely useful. Try to understand how the loop for the top sliders works. Try to understand why the second loop does not - even though they are very similar.
To help you learn about closures, there is a Closure Tutorial Video, and an optional Functional Programming Tutorial (repo) which is a small workbook that covers the important concepts..
There are a lot of comments in the code for 01-09-03.html. Take the time to try to understand this code.
While programming techniques, like closures, are not necessarily “graphics” - learning them is part of the class. You can expect exam questions about closures.
Even more infinite loop examples
The box 01-09-04.html has some more complex versions of that infinite loop from the previous box. Be sure to look at the code to understand how it works! These kinds of things (looking at input elements within animation loops) will happen all of the time when we start doing graphics programming.
view - look at the box and experiment with it
examine - look at the code for the box
edit - change the box's content
rubric - several steps are suggested in the rubric page - form elements on page in rubric
01-09-04.html
Event Loops and Animation Loops
On this page we saw how the browser’s mechanism for event loops causes us to need to write animation loops in a special way. Make sure you understand this, before moving onto Next: Page 10 - Animation Loops: Timing where we will discuss controlling timing.
And remember, there was a box on this page that required you to actually edit a program and check off a rubric item. (it was 01-09-03)
Next: Page 10 - Animation Loops: Timing