Disadvantages of traditional animation

In actual projects, we often encounter the need to generate animation. The traditional method is to use setTimeout and setInterval to achieve this, but timer animation has two disadvantages:

  • The interval is not easy to handle, set too short browser redraw frequency too fast will cause performance problems, too slow and looks like PPT is not smooth, the industry recommended interval is 16.66… (Display refresh rate is 60Hz, 1000ms/60)
  • Browser UI thread congestion, if the UI thread has a lot of rendering tasks to complete, the animation to be executed will be shelved.

HTML5 adds requestAnimationFrame to address these issues

RequestAnimationFrame?

MDN

Window. RequestAnimationFrame () method tells the browser you want to perform the animation and request the browser before the next redraw call the specified function to update the animation. This method takes as an argument a callback function that is called before the browser redraws.

  • 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

  • RequestAnimationFrame will not be redrawn or reflow in hidden or invisible elements, which of course means less CPU, GPU, and memory usage

  • RequestAnimationFrame is a browser-specific API for animation that optimizes method calls at runtime and pauses animation automatically if the page is not active, saving CPU overhead

usage

You can directly call requestAnimationFrame (), also can through the window. The window to call requestAnimationFrame (). RequestAnimationFrame () to receive a function as a callback, returns an ID value, through the ID value passed to the window. The cancelAnimationFrame () you can cancel the animation.

Examples given on MDN:

var start = null;
var element = document.getElementById('SomeElementYouWantToAnimate');
element.style.position = 'absolute';

function step(timestamp) {
  if(! start) start = timestamp; var progress = timestamp - start; element.style.left = Math.min(progress / 10, 200) +'px';
  if(progress < 2000) { window.requestAnimationFrame(step); }}Copy the code

example

Let’s try to create a square that rotates and gradually Narrows, and when it gets narrow enough, it will go back and forth. Jsbin to see the effect

var rotate = 0;
var width = 400;
var element = document.getElementById('box');

function step(timestamp) {
    rotate += 10
    element.style.transform = `rotate(${rotate}deg)`;
    window.requestAnimationFrame(step);
}

function small(timestamp) {
    width = width - 1
    element.style.width = width + 'px';
    if (width <= 50) {
        window.requestAnimationFrame(big);
    } else{ window.requestAnimationFrame(small); }}function big() {
    width = width + 1
    element.style.width = width + 'px';
    if (width >= 400) {
        window.requestAnimationFrame(small);
    } else {
        window.requestAnimationFrame(big);
    }
}

window.requestAnimationFrame(step);
window.requestAnimationFrame(small);
Copy the code

Browser Compatibility

Let’s look at the compatibility on Can I Use:

If you must be compatible with IE, you can use timer to do compatibility:

(function () {
    var lastTime = 0;
    var vendors = ['webkit'.'moz'];
    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*/ var currTime = new Date().getTime(); */ var currTime = new Date().callback (); 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