6. Timers


In This Chapter

Learn how to delay when your code runs

Figure out several ways to run your code repeatedly without blocking your entire app


By default, your code runs synchronously. That is a fancy of way of saying that when a statement needs to execute, it executes immediately. There are no ifs, ands, or buts about it. The concept of delaying execution or deferring work to later isn’t a part of JavaScript’s default behavior. That doesn’t mean the ability to delay work to a later time doesn’t exist! If you swerve just slightly off the main road, there are three functions that allow you to mostly do just that (and more). Those functions are setTimeout, setInterval, and requestAnimationFrame.

In this chapter, we look at what each of these function do and other good stuff that comes along with learning more about some of the basic components JavaScript provides for helping your code do interesting things.

Onwards!

Meet the Three Timers

Like you saw a few pixels ago, the main suspects of this chapter are going to be the setTimeout, setInterval, and requestAnimationFrame functions. In the following sections, let’s look at each of these functions in greater detail and figure out a reason for their existence.

Delaying with setTimeout

The setTimeout function enables you to delay executing some code. The way you use it is pretty simple. This function makes it possible for you to specify what code to execute and how many milliseconds (aka 1/1000 of a second) to wait before the code you specified executes.

Putting that into JavaScript, it looks something like this:

var timeID = setTimeout(someFunction, delayInMilliseconds);

Going a bit more example-ish, if I wanted to call a function called showAlert after 5 seconds, the setTimeout declaration would look as follows:

function showAlert() {
  alert("moo");
}

var timeID = setTimeout(showAlert, 5000);

Pretty simple, right? Now, let’s talk about something less interesting that I cover just for completeness. That something has to do with the timeID variable that is initialized to our setTimeout function. It isn’t there by accident. If you ever wanted to access this setTimeout timer again, you need a way to reference it. By associating a variable with our setTimeout declaration, we can easily accomplish that.

Now, you may be wondering why we would ever want to reference a timer once we’ve created it. There aren’t too many reasons. The only reason I can think of would be to cancel the timer. For setTimeout, that is conveniently accomplished using the clearTimeout function and passing the timeout ID as the argument:

clearTimeout(timeID);

If you are never planning on cancelling your timer, you can just use setTimeout directly without having it be part of the variable initialization.

Anyway, moving past the technical details on how to use setTimeout, let’s talk about when you would commonly use it in the real world. As you will find out eventually, especially if you are doing front-end/user interface (UI) development, deferring some action to a later time is more common than you might think. Here are some examples that I ran into just in the recent past:

1. A menu slides in, and after a few seconds of the user no longer playing with the menu, the menu slides away.

2. You have a long running operation that is unable to complete, and a setTimeout function interrupts that operation to return control back to the user.

3. My favorite is where you use the setTimeout function to detect whether a user is inactive or not (See: http://bit.ly/kirupaDetectIdle).

If you do a search for setTimeout on this site or Google, you’ll see many more real-world cases where setTimeout proves very useful.

Looping with setInterval

The next timer function we are going to look at is setInterval. The setInterval function is similar to setTimeout in that it also enables you to execute code after a specified amount of time. What makes it different is that it doesn’t just execute the code once. It keeps on executing the code in a loop forever.

Here is how you would use the setInterval function:

var intervalID = setInterval(someFunction, delayInMilliseconds);

Except for the function name, the way you use setInterval is even identical to setTimeout. The first argument specifies the inline code or function you would like to execute. The second argument specifies how long to wait before your code loops again. You can also optionally initialize the setInterval function to a variable to store an interval ID—an ID that you can later use to do exciting things like cancel the looping.

OK! Now that we’ve seen all that, here is an example of this code at work for looping a function called drawText with a delay of 2 seconds between each loop:

function drawText() {
  document.querySelector("p").textContent += "# ";
}

var intervalID = setInterval(drawText, 2000);

Just make sure you have a p element somewhere in your page that will act as the target our code will add the # character to.

If you wish to cancel the looping, you can use the appropriately named clearInterval function:

clearInterval(intervalID);

Its usage is similar to its clearTimeout equivalent. You pass in the ID of the setInterval timer instance that you optionally retrieved while setting up your setInterval in the first place.

Here is some interesting trivia. For the longest time, setInterval was the primary function you had for creating animations in JavaScript. To get something running at 60 frames a second, you would do something that looks as follows:

// 1000 divided 60 is the millisecond value for 60fps
window.setInterval(moveCircles, 1000/60);

Towards the end of this chapter, you’ll see some links to examples and articles I’ve written on the web where setInterval is part of a larger, more realistic example.

Animating Smoothly with requestAnimationFrame

Now, we get to one of my favorite functions ever: requestAnimationFrame. The requestAnimationFrame function is all about synchronizing your code with a browser repaint event. What this means is pretty simple. Your browser is busy juggling a billion different things at any given time - fiddling with layout, reacting to page scrolls, listening for mouse clicks, displaying the result of keyboard taps, executing JavaScript, loading resources, and more. At the same time your browser is doing all of this, it is also redrawing the screen at 60 frames per second...or at least trying its very best to.

When you have code that is designed to animate something to the screen, you want to ensure your animation code runs properly without getting lost in the shuffle of everything else your browser is doing. Using the setInterval function mentioned earlier doesn’t guarantee that frames won’t get dropped when the browser is busy optimizing for other things. To avoid your animation code from being treated like any other generic piece of code, you have the requestAnimationFrame function. This function gets special treatment by the browser. This special treatment allows it to time its execution perfectly to avoid dropped frames, avoid unnecessary work, and generally steer clear of other side effects that plague other looping solutions.

The way you use this function starts off a bit similar to setTimeout and setInterval:

var requestID = requestAnimationFrame(someFunction);

The only real difference is that you don’t specify a duration value. The duration is automatically calculated based on the current frame rate, whether the current tab is active or not, whether your device is running on battery or not, and a whole host of other factors that go beyond what we can control or understand.

Anyway, this usage of the requestAnimationFrame function is merely the textbook version. In real life, you’ll rarely make a single call to requestAnimationFrame like this. Key to all animations created in JavaScript is an animation loop, and it is this loop that we want to throw requestAnimationFrame at. The result of that throw looks something as follows:

function animationLoop() {
  // animation-related code

  requestAnimationFrame(animationLoop);
}

// start off our animation loop!
animationLoop();

Notice that our requestAnimationFrame calls the animationLoop function fully from within the animationLoop function itself. That isn’t a bug in the code. While this kind of circular referencing would almost guarantee a hang, requestAnimationFrame’s implementation avoids that. Instead, it ensures the animationLoop function is called just the right amount of times needed to ensure things get drawn to the screen to create smooth and fluid animations. It does so without freezing the rest of your application functionality up.

To stop a requestAnimationFrame function, you have the cancelAnimationFrame function:

cancelAnimationFrame(requestID);

Just like you’ve seen several times with functions of this sort, cancelAnimationFrame takes the ID value of our requestAnimationFrame function that is returned when you call it. If you plan on using cancelAnimationFrame, then you can modify our earlier animationLoop example as follows:

var requestID;

function animationLoop() {
  // animation-related code

  requestID = requestAnimationFrame(animationLoop);
}

// start off our animation loop!
animationLoop();

Notice that our call to requestAnimationFrame always sets the value of requestID, and you can use requestID as the argument to cancelAnimationFrame to stop our loop.


Image Tip

Just a quick reminder for those of you reading these words in the print or e-book edition of this book: If you go to www.quepublishing.com and register this book, you can receive free access to an online Web Edition that not only contains the complete text of this book but also features a short, fun interactive quiz to test your understanding of the chapter you just read.

If you’re reading these words in the Web Edition already and want to try your hand at the quiz, then you’re in luck – all you need to do is scroll down!


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.50.87