RequestAnimationFrame overview of

RequestAnimationFrame is a browser interface for timed loops, similar to setTimeout, that redraw a web page frame by frame. RequestAnimationFrame brings together all DOM operations in each frame in a single redraw or reflow, and the redraw or reflow interval closely tracks the browser refresh rate, which is typically 60 frames per second, or 1000/60=16.7ms. RequestAnimationFrame has the biggest advantage over setTimeout in that it is up to the system to determine the timing of callback function execution. RequestAnimationFrame takes full advantage of the refresh mechanism of the display and saves system resources. When the page is invisible or unavailable, the browser stops the animation, which means less CPU and less memory consumption.

The browser lost frames

Before requestAnimationFrame, if we were using JS for animation effects, we would normally use setTimeout and setInterval, but, The timing of the callback you specify in setTimeout or setInterval is not guaranteed. It will be executed at some point in the animation frame, probably at the end of the frame, which means we may lose the information for that frame.

For example, when the animation is drawn with a JavaScript timer resolution of 10ms, you will see a timing mismatch, as shown below.

The top line represents the 16.7ms display frequency displayed on most monitors, and the bottom line represents a typical setTimeout of 10ms. Every three draws (indicated by red arrows) cannot be drawn because another draw request occurred before the display refresh interval. This overdraft can cause the animation to stutter, as every third frame is lost. Reduced timer resolution can also have a negative impact on battery life and reduce the performance of other applications. The requestAnimationFrame method (defined in the World Wide Web Consortium (W3C) as a timing control specification for script-based animation) solves the frame loss problem because it enables the application to notify (and only if) the browser of the need to update the page display. As a result, the application matches the browser painting interval perfectly and uses only the right amount of resources. Switching from setTimeout to requestAnimationFrame is easy because they both schedule a callback. For continuous animation, requestAnimationFrame is called again after the animation function is called.

Using requestAnimationFrame

RequestAnimationFrame takes a callback function as an argument. This callback is called before the browser redraws.

requestID = window.requestAnimationFrame(callback); 
Copy the code

When using requestAnimationFrame, you just need to call it repeatedly.

function repeatOften() {
  // Do whatever
  requestAnimationFrame(repeatOften);
}

requestAnimationFrame(repeatOften)
Copy the code

To cancel the redraw, use the cancelAnimationFrame method, which takes an integer value representing the task ID returned by requestAnimationFrame.

window.cancelAnimationFrame(requestID);
Copy the code

RequestAnimationFrame compatibility

If requestAnimationFrame and cancelAnimationFrame are not supported, requestAnimationFrame and cancelAnimationFrame are not supported because there are compatibility issues with requestAnimationFrame and different browsers require different prefixes. SetTimeout and clearTimeout are used. Compatibility encapsulation:

  • Simplified version
window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { // To make setTimteout as close to 60 frames per second as possible, window.settimeout (callback, 1000 / 60) } window.cancelAnimationFrame = window.cancelAnimationFrame || Window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame || function (id) { window.clearTimeout(id) };Copy the code
  • Updated version
(function() { var lastTime = 0; var vendors = ['webkit', 'moz', 'ms']; for(var x = 0; x < vendors.length && ! window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (! window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (! window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }} ());Copy the code

Now that we know about the requestAnimationFrame function, let’s put it to use and create a progress bar effect

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, < span style>. Container {width: 400px; margin: 50px auto; } .wrap { height: 10px; border-radius: 5px; overflow: hidden; background-color: #31493C; } .box { height: 6px; background-color: #B3EFB2; border-radius: 3px; margin: 2px; } .row { display: flex; justify-content: center; align-items: center; } .btn { cursor: pointer; margin: 0 10px; } </style> </head> <body> <div class="container"> <div class="wrap"> <div class="box" id="box"></div> </div> <div Class = "row" > < div class = "TXT" > < span id = "TXT" > % 0 < / span > < / div > < div class = "BTN" id = "BTN" > suspended < / div > < / div > < / div > < script > let box = document.getElementById('box'); let btn = document.getElementById('btn'); let handel = 0; let $width = 0; function setWidth (params) { box.style.width = $width + 'px'; handel = window.requestAnimationFrame(setWidth); $width <= 396 ? $width++ : btn.style.display = 'none'; document.getElementById('txt').innerText = Math.ceil($width/400*100) } setWidth(); btn.addEventListener('click', function () { if (handel) { window.cancelAnimationFrame(handel); handel = 0; Btn.innertext = 'play'} else {setWidth(); Btn. innerText = 'pause'}}, false) </script> </body> </ HTML >Copy the code

The resources

  • Nguyen Yifeng, requestAnimationFrame
  • Zhang Xinxu, CSS3 animation is so strong, requestAnimationFrame and wool?
  • Paul Irish, requestAnimationFrame for Smart Animating
  • RequestAnimationFrame caniuse,
  • Timing control for script-based animations (“requestAnimationFrame”)