Introduction:
This article discusses how to improve the animation performance by using the requestanimationframe API rather than the setinterval/setTimeout method. Of course, we will show you the complete code example of requestanimationframe in action.
Requestanimationframe is now supported by mainstream browsers, although some browsers need to be prefixed. Erik Moller has written a polyfill that can support requestanimationframe in all browsers. We will discuss it in more detail later. Let's start from scratch...
Bad old method
To show how good the requestanimationframe is, we must first look at the old method we used for animation. I'm sure I don't need to tell you that you may have used setTimeout and setinterval to create an animation as early as Mozilla conducted the first rolling requestanimationframe experiment. I suppose you are familiar with these two methods, so I will not explain them in depth. If you want to learn more, here is an article about John resig: How JavaScript timers work.
I don't want to disregard these old methods. Unfortunately, they do have some shortcomings. First, when switching to a different tag, the Javascript timer will continue to work even when the corresponding page is minimized. The consequence is that the browser continues to run the invisible animation, which leads to excessive animation rendering, a waste of CPU cycles, and additional power consumption. This is especially bad for mobile devices.
Second, the timer will not only continue to run invisible animations, but also wait in queue for their callback functions when the time is reached. Let me explain why this situation sometimes causes problems-that is to say, you have not completed your work well, for some reason, the time required to complete the callback function is longer than the time required to set the timer. Once the timer time reaches, they will queue up to another callback function. Although the previous one has not been completed yet. Over time, this process has been repeated, and you can quickly queue to almost countless timers, which will cause the browser to stop running. Figure 1 details the problem.
Figure 1: If the callback function is executed longer than the timer, a large number of queuing callback functions will block the browser.
However, even if your callback function does not take more time than the timer, setTimeout and setinterval are still not the best choice. They can only re-draw the animation at a fixed rate, so to ensure smooth animation, we tend to choose a frequency that is slightly higher than the display refresh. However, some frames are drawn before the display refresh rate is ready to draw the animation, so they are discarded, which leads to the problem of over-painting. Figure 2 details the problem.
Image 2: frame skipping can lead to higher CPU usage and battery consumption, and sometimes unstable animations.
These disadvantages are even more dangerous when these methods are used to implement loop animation. In such scenarios, such as in games or crazy experiments like my hipster dog, loop animation leads to endless queues waiting for new callback functions. If you want to learn more about the history of network loop animation. When setTimeout and setinterval are used, what is the behavior of loop animation and how requestanimationframe changes our code. I recommend that you read better JavaScript animations with requestanimationframe written by Nicholas zakas, which is discussed in depth.
Introduction to requestanimationframe
Requestanimationframe is an API you expect: It transfers the role of scheduling animation painting directly to the browser. The browser can do better, because it knows what the browser mechanism is!
Requestanimationframe is part of the w3ctiming Control for script-based animations API.
What does requestanimationframe do?
The browser is very familiar with the tab and window states, which parts of the webpage are visible or invisible, when the browser plans to draw, and which other animations are also running and which are visible. We have previously discussed how to allow browsers to control animations and allow browsers to use information to optimize animation scheduling. requestanimationframe uses JavaScript timers to track events. Therefore, the workflow of requestanimationframe is as follows:
- First, Raf (request animation frame) Only draws animations visible to users. This means that RAF will pause the animation of hidden tabs, minimized windows, or hidden pages until these windows or pages are visible, so as not to waste the CPU and battery life.
- Second, frames are drawn only when the browser is ready to draw and no other frames are waiting to be drawn. This means that these situations are not possible: to draw an animation using requestanimationframe, You need to queue More Than One callback function or paralyze the browser.
- Third, frames are drawn only when the browser is ready to draw and no other frames are waiting to be drawn. No unnecessary frames are drawn. So the animation is smoother, and the use of CPU and battery is further optimized.
I just said that there is no additional callback function queue until the current animation is drawn and rendered. However, if you call requestanimationframe () more than once for each callback, there will be a callback queue, so there will be an additional callback function.
At the same time, the browser can have several animations on the same page in a backflow and re-painting cycle.
Requestanimationframe does not do anything
Requestanimationframe does not:
- Sets continuous animation. Raf only schedules one update. This update is identified by an ID number and a specific request is returned. If a subsequent animation frame is required, requestanimationframe will be called again in the callback function. To stop the animation, you can use cancelanimationframe (ID ).
- Make sure that RAF is drawn only when needed.
- Ensure the animation synchronization. For example, if you start two animations at the same time, but one of the animations is in the visible area and the other is not in the visible area, the visible animations are always drawn, and the other is not; when the invisible animation is re-visible, they may not be synchronized. If you need to ensure their synchronization, you need to pay attention when writing code. You can ensure that the State of all the animations to be synchronized is determined by an invisible parameter (for example, the starting time of an animation group .) This is opposite to the previous frame of each animation.
- Draw until the callback function execution is complete. Even if you try to trigger a backflow intermediate callback, under normal circumstances, any method that can trigger a reflux, re-painting. For example, getcomputedstyle ().
How to Use requestanimationframe
RAF is now supported by all modern browsers, but some browsers need to be prefixed. As of this article, the prefix or no prefix is added as follows:
- Opera: no prefix opera15 +
- Chrome: no prefix after Version 24
- Safari: prefix
- Firefox: Add a prefix, although the prefix is not added after Version 23.
- IE: no prefix after ie10
However, to make your code compatible at all stages, you should use Erik Moller's polyfill, which provides powerful cross-browser support, optimized based on Paul Irish's fantastic original groundwork on the subject.
The following is the simple code of the frog animation demonstration:
var requestId = 0;var animationStartTime = 0;function animate(time) { var frog = document.getElementById("animated"); frog.style.left = (50 + (time - animationStartTime)/10 % 300) + "px"; frog.style.top = (185 - 10 * ((time - animationStartTime)/100 % 10) + ((time - animationStartTime)/100 % 10) * ((time - animationStartTime)/100 % 10) ) + "px"; var t = (time - animationStartTime)/10 % 100; frog.style.backgroundPosition = - Math.floor(t / (100/2)) * 60+ "px"; requestId = window.requestAnimationFrame(animate);}function start() { animationStartTime = window.performance.now(); requestId = window.requestAnimationFrame(animate);}function stop() { if (requestId) window.cancelAnimationFrame(requestId); requestId = 0;}
Requestanimationframe is a method that sends a signal to the browser indicating that a script-based animation needs to be re-sampled by inputting the callback into the callback list queue of the animation frame request. It has a list of callback function IDs, which are waiting for execution. Call requestanimationframe to return the ID (requestid). The ID identifies the callback of the inserted queue. This ID can be used to cancel the callback and cancelanimationframe (ID) is used to cancel the callback.
The requestanimationframe method calls back the parameter last night. The callback function needs to be executed to draw a new animation frame (animation ). callback, in turn, is a function. The timestamp when the animation is updated is used as the parameter (time ).
The timestamp is the result of calling the now method to optimize performance. You need to determine that any other time measurements you want to compare are also domhighrestimestamp -- in the above example, we call window. performance. Now and store the results using the animationstarttime variable. Then, in the animation function, we compare the start time and current time of each frame to calculate the position of the frog in each case.
When writing an animation, In case you encounter an old tutorial, note that the animationstarttime attribute has been created, but it has been discarded, so you must track the start time as shown above.
Access my requestanimationframe demo
Summary
In this article, we will discuss how requestanimationframe improves JavaScript animation performance and how you can use it to be compatible with all browsers. I hope this article will inspire you to try more cool animation effects-you can update any animation Code implemented in the old way.
Link to better performance with requestanimationframe
Requesanimationframe (better performance with requestanimationframe) with better performance)