RequestAnimationFrame is better than setTimeoutsetInterval because it is an API provided by the browser for animation. At runtime, the browser automatically optimizes the method call. If the page is not activated, the animation will be automatically paused, effectively saving CPU overhead. This article will introduce in detail how to use requestAnimationFrame to implement js animation and use requestAnimationFrame to achieve good js animation performance. First, let's briefly introduce the advantages of requestAnimationFrame over setTimeout and setInterval?
Example 1:
RequestAnimationFrame has two advantages over setTimeout and setInterval:
1. requestAnimationFrame gathers all DOM operations in each frame and completes the re-painting or backflow. The re-painting or backflow interval closely follows the refreshing frequency of the browser, generally, this frequency is 60 frames per second.
2. In hidden or invisible elements, requestAnimationFrame will not be repainted or reflux, which of course means less cpu, gpu, and memory usage.
Like setTimeout and setInterval, requestAnimationFrame is a global function. After requestAnimationFrame is called, it requires the browser to re-paint the image at its own frequency. It receives a callback function as a parameter and calls this function when the browser re-painting is about to begin, the time when the callback function is called is passed in as a parameter. Because requestAnimationFrame is only effective at one time, to achieve the animation effect, you must continuously call requestAnimationFrame, as we do with setTimeout. The requestAnimationFrame function returns a resource identifier, which can be passed as a parameter to the cancelAnimationFrame function to cancel the requestAnimationFrame callback. Is it similar to clearTimeout of setTimeout.
Therefore, requestAnimationFrame is a performance-optimized setTimeout tailored for animations. The difference is that requestAnimationFrame does not specify the time when the callback function runs, instead, the callback is implemented based on the built-in refresh frequency of the browser, which of course can achieve the best animation effect of the browser.
Currently, some browsers that support requestAnimationFrame are their own private implementations, so they must be prefixed. For browsers that do not support requestAnimationFrame, we can only use setTimeout, because they are used almost the same way, therefore, the compatibility between the two is not difficult. For browsers that support requestAnimationFrame, we use requestAnimationFrame. If not, we use traditional setTimeout for downgrading. Encapsulate them to get a unified API compatible with all major browsers.
Code can be viewed here: https://gist.github.com/chaping/88813f56e75b0fd43f8c
Var lastTime = 0; var prefixes = 'webkit moz MS o '. split (''); // Each browser prefix var requestAnimationFrame = window. requestAnimationFrame; var cancelAnimationFrame = window. cancelAnimationFrame; var prefix; // get the implementation form of requestAnimationFrame and cancelAnimationFrame in the current browser by traversing the prefixes of Each browser. for (var I = 0; I <prefixes. length; I ++) {if (requestAnimationFrame & cancelAnimationFrame) {break;} prefix = prefixes [I]; requestA NimationFrame = requestAnimationFrame | window [prefix + 'requestanimationframework']; cancelAnimationFrame = cancelAnimationFrame | window [prefix + 'canonicalizionframework'] | window [prefix + 'sequence'] // if the current browser does not support requestAnimationFrame and cancelAnimationFrame, it will return to setTimeoutif (! RequestAnimationFrame |! CancelAnimationFrame) {requestAnimationFrame = function (callback, element) {var currTime = new Date (). getTime (); // to make the setTimteout effect as close as possible to 60 frames per second var timeToCall = Math. max (0, 16-(currTime-lastTime); var id = window. setTimeout (function () {callback (currTime + timeToCall) ;}, timeToCall); lastTime = currTime + timeToCall; return id ;}; cancelAnimationFrame = function (id) {window. clearTimeout (id) ;};}// get APIwindow compatible with various browsers. requestAnimationFrame = requestAnimationFrame; window. cancelAnimationFrame = cancelAnimationFrame;
In this way, we can use requestAnimationFrame and cancelAnimationFrame in all browsers.
The following is a simple example to illustrate how to use requestAnimationFrame for animation. The code below will move the p with id as demo to the right in the form of animation to 300px.
Script var demo = document. getElementById ('Demo'); function rander () {demo. style. left = parseInt (demo. style. left) + 1 + 'px '; // move 1px to the right of each frame} requestAnimationFrame (function () {rander (); // stop if (parseInt (demo. style. left) <= 300) requestAnimationFrame (arguments. callee) ;}); script
Example 2:
For a long time, JavaScript animation is implemented by timer and interval. Although CSS transitions and animations are used to make it easier for Web developers to implement animations, the JavaScript-based animations have rarely changed over the years. It was not until the release of Firefox 4 that the first method to improve JavaScript animation was introduced. But we need to fully understand the improvements, which helps us understand how web Animation evolves and improves.
Timer
The first mode used to create an animation is called using the setTimeout () chain. For a long period of time in Netscape 3's hayday, developers all remember a fixed latest market status bar that is everywhere on the network. It is usually similar to this:
(Function () {var msg = "new advertisement", len = 25, pos = 0, padding = msg. replace (/. /g ,""). substr (0, len), finalMsg = padding + msg; function updateText () {var curMsg = finalMsg. substr (pos ++, len); window. status = curMsg; if (pos = finalMsg. length) {pos = 0;} setTimeout (updateText, 100) ;}settimeout (updateText, 100 );})();
If you want to test this code in your browser, you can create
The label is used to simulate window. status, for example, newsticker example.
This annoying web model was later hit by window. with the release of Explorer 4 and Netscape 4, the browser gives developers more control permissions on page elements for the first time. In this way, there is a new Animation Mode that uses javascript to dynamically change the element size, position, color, and so on. For example, the following is an animation that changes the width of p to 100% (similar to a progress bar ):
(function(){ function updateProgress(){ var p = document.getElementByIdx_x("status"); p.style.width = (parseInt(p.style.width, 10) + 5) + "%"; if (p.style.width != "100%"){ setTimeout(updateProgress, 100); } } setTimeout(updateProgress, 100); })();
Although the animation on the page is different, the basic principle is the same: make a change, use setTimeout () interval to update the page, and then setTimeout to execute the next change, this process is executed repeatedly until the animation is completed (see progress bar animation). The early status bar animation technology is the same, but the animation is different.
Interval animation Intervals
With the successful introduction of animations into the web, a new exploration begins. One animation is no longer enough. Now multiple animations are needed. The first attempt was to create multiple animation loops for each animation. It was a bit complicated to create multiple animations using setTimeout () in earlier browsers, so developers started to use setInterval () create a single animation loop to manage all the animations on the page, and a basic animation using wetInterval () is as follows:
(function(){ function updateAnimations(){ updateText(); updateProgress(); } setInterval(updateAnimations, 100); })();
Create a small animation library. The updateAnimations () method cyclically executes and changes each animation (with a news stock and progress bar running together. If no animation needs to be updated, this method can exit without doing anything, or even stop the animation loop until more animation updates are ready.
The tricky problem with animation is the latency. On the one hand, the interval must be short enough so that different animations can be smoothly carried out. On the other hand, it must be long enough so that the browser can complete rendering. The refresh frequency of most browsers is 60 HZ, that is, 60 refresh times per second. Most browsers do not refresh more frequently than this because they know that end users cannot have a better experience.
In view of this, the optimal interval for smooth animation is 1000 ms/60, about 17 ms. At this frequency, you will see smooth animations, because you are most close to the frequency that the browser can achieve. Compared with previous animations, you will find that the animation at the 17ms interval is smoother and faster (because the animation updates are more frequent and no other modifications are made ), multiple animations may require throttling, so that the 17 Ms animation can be completed too quickly.
Problem
Even if the setInterval ()-based animation loop is more efficient than the setTimeout ()-based animation loop, there is still a problem. Neither setInterval () nor setTimeout () can be precise, this latency means that the second parameter you specify only indicates when the code will be added to the UI thread queue that may be executed by the browser. If there is other work in the queue before this, the code will not be executed until it is completed. In short, the latency in milliseconds does not indicate when the code will be executed, but when the code will be added to the queue. If the UI thread is busy or processing user actions, the code will not be executed immediately.
The key to a smooth animation is to understand when the next frame will be executed. Until now, there is no way to ensure that the next frame will be drawn in the browser. With the increasing popularity of new browser-based games, developers are increasingly disappointed with the inaccuracy of setInterval () and setTimeout.
The browser's timer resolution increases this problem. The timer is not precise to milliseconds. Here are some common timer resolutions:
Internet Explorer 8 and earlier 15.625 ms
Internet Explorer 9 and later 4 ms.
Firefox and Safari ~ 10 ms.
Chrome has a timer 4 ms.
IE versions earlier than version 9 have a resolution of 15.625, So 0 ~ Any value between 15 May be 0 or 15, but there is no difference. The timer resolution of IE9 is improved to 4 ms, but it is not specific when it involves animation. The timer resolution of chrome is 4 ms, and that of firefox and safari is 10 ms. Therefore, even if you set the interval to the best display effect, you just get this approximate value.
MozRequestAnimationFrame
Mozilla's Robert o'callahan was thinking about this and came up with a unique solution. He pointed out that the advantage of CSS transitions and animations is that the browser knows which animations will happen, so get the correct interval to refresh the UI. In javascript animation, the browser does not know that the animation is happening. His solution is to create a javasrequestanimationframe () method to tell the browser which javascript code is being executed, which optimizes browsing after executing some code.
The mozRequestAnimationFrame () method accepts a parameter and is a function called before screen re-painting. This function is used to generate the appropriate dom style changes, which are used in the next re-painting. You can call javasrequestanimationframe () in the same way as calling setTimeout (). For example:
function updateProgress(){ var p = document.getElementByIdx_x("status"); p.style.width = (parseInt(p.style.width, 10) + 5) + "%"; if (p.style.left != "100%"){ mozRequestAnimationFrame(updateProgress); } }
Required requestanimationframe (updateProgress );
Because javasrequestanimationframe () only runs a given function once, you need to call it again in the next UI animation. You also need the same method to manage when to stop calling. Cool. It is a very smooth animation enhancement instance.
Therefore, javasrequestanimationframe () solves the problem that the browser does not know how many Javascript animations are being executed and how many Javascript animations are being executed. However, if you do not know when your code is actually executed, this solution also solves the problem.
The function passed to mozRequestAnimationFrame () is actually a time code for the next re-painting (measured in milliseconds from January 1, January 1, 1970 ). This is very important: mozRequestAnimationFrame () actually lists the vertices to be repainted and tells you the time they are in. In this way, you can decide how to better adjust your animation.
To obtain the time of the previous re-painting, you can query the mozAnimationStartTime, which contains the time code of the previous re-painting. After the callback is passed, this value can be used to calculate the time used for the next screen re-painting. The typical mode of using these values is as follows:
function draw(timestamp){ //calculate difference since last repaint var diff = timestamp - startTime; //use diff to determine correct next step //reset startTime to this repaint startTime = timestamp; //draw again mozRequestAnimationFrame(draw); } var startTime = mozAnimationStartTime; mozRequestAnimationFrame(draw);
The key is that when the call is not called through callback for the first time, the mozAnimationStartTime is the time that passes to the mozRequestAnimationFrame. In the callback function, the mozAnimationStartTime is the average value of the Time Code passed in through the parameter.
WebkitRequestAnimationFrame
When many people are loyal to chrome, The webkitRequestAnimationFrame () method is created immediately. This version is slightly different from firefox in two aspects. On the one hand, it does not pass the time code through the callback function, you will not be able to know when the next re-painting will happen, on the other hand, it adds the second optional parameter to determine which DOM element has changed. Therefore, if you know which part of the page is repainted, you can limit the area where the repainting occurs.
I should not be surprised if there is any corresponding mozAnimationStartTime, because it is not very helpful if there is no next re-painting time information. Yes, but webkitCancelAnimationFrame () cancels the previously planned re-painting.
If you do not need accurate time differences, you can use the following method to create an animation for Firefox4 and chrome10 +:
function draw(timestamp){ //calculate difference since last repaint var drawStart = (timestamp || Date.now()), diff = drawStart - startTime; //use diff to determine correct next step //reset startTime to this repaint startTime = drawStart; //draw again requestAnimationFrame(draw); } var requestAnimationFrame = window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame, startTime = window.mozAnimationStartTime || Date.now(); requestAnimationFrame(draw);
This mode uses an available method to create a loop animation with the idea of how much time it takes. Firefox uses the time code information, while Chrome is a time object that is not accurate by default. In this mode, the difference in time gives you an idea of how much time has passed, but it does not tell you when Chrome will redraw the next time. However, this is better than the vague concept of how much time has passed.
Summary
The introduction of the mozRequestAnimationFrame () method plays an important role in promoting the history development of Javascript animation and web. As mentioned above, the JavaScript animation is almost the same as that in the early stage of JavaScript. As browsers gradually launch CSS transitions and animations, we are very happy to see the attention of JavaScript-based animations, as these will become more important in the field of game based and more closely linked to the CUP. Know when Javascript will try animation, and allow the browser to do more optimization, including stopping the process when the tab is in the background or when the power of the mobile device is too low.
The requestAnimationFrame () API is now being drafted by W3C and is being made part of the Web stage by Mozilla and Google. We are glad to see that these two groups are so quickly compatible (may not be completely.
Use RequestAnimFrame
For all DOM operations in a single detection, Layout and painting are performed only once.
If the animation element is hidden, the painting will not be used.
Window. requestAnimFrame = (function () {return window. requestAnimationFrame | window. webkitRequestAnimationFrame | window. required requestanimationframe | window. oRequestAnimationFrame | window. msRequestAnimationFrame | function (callback) {window. setTimeout (callback, 1000/60) ;}}) (); // call function animationLoop (elem) {requestAnimFrame (animationLoop); // logic} Orwindow. requestAnimFrame = (function (w, r) {w ['R' + r] = w ['R' + r] | w ['webkitr' + r] | w ['mozr '+ r] | w ['msr' + r] | w ['oR' + r] | function (c) {w. setTimeout (c, 1000/60) ;}; return w ['R' + r] ;}) (window, 'equestanimationframework ');
The above two sample codes illustrate how to use requestAnimationFrame to achieve good js animation performance. I hope you will like it.