The introduction

In daily development, we often use JS timer API(setTimeout setInterval), we will only stay in the use level, rarely to carefully think about the differences, advantages and disadvantages between the two.

Why does HTML5 provide requestAnimationFrame🤔 when you can use setTimeout setInterval Css3?

This article will take you through setTimeout, setInterval, requestAnimationFrame.

Pre-animation knowledge

Here is a brief introduction to the formation of animation reasons and basic concepts, easy to understand later reading.

1. Computer screen refresh rate and browser redraw times

  • Screen refresh rate refers to1sNumber of internal screen refreshes.
  • The average computer’s screen refresh rate is zero1 s 60 times(1000ms / 60 ≈ 16.7ms | 60FPS), that is, each16.7 msIt refreshes the screen. Of course, this number depends on resolution, graphics card, screen size, and other factors.
  • Because the average computer refresh rate is60FPS, so most browsers limit the number of redraws, generally not more than the number of redraws on the computer, because the user experience is not improved by exceeding that frequency.

2. How is animation formed?

Animation is the visual residue caused by the naked eye, through the continuous playing of static images to form a dynamic illusion. When 24 images are played in a row for 1 second (24FPS), a smooth animation can be formed. Normally, the computer refreshes at 60FPS.

3. The way the Web implements animation

  • css:animation,transition
  • js: setTimeout,setInteval
  • html: canvas,svg
  • requestAnimationFrame, etc…

This article focuses on the setTimeout, setInterval, and requestAnimationFrame apis.

The body of the

setInterval

The setInterval method calls a function or executes an eval at a specified interval (milliseconds).

Key: The interval specified by the timer that indicates when the callback function is added to the message queue, not when the callback function is executed. The actual time when the function is executed is uncertain, depending on when the callback is picked up by the main thread’s event loop and executed.

parameter

  • function/code
    • Required Function/string to be called repeatedly. Is compiled to when it is a stringjsCode execution.
  • delay
    • Required periodicallyfunction/codeTime interval in milliseconds.
    • Note:HTML5Specifies that the minimum execution interval is10msWhen less than10ms, the default value is10ms.
  • args1... argsN
    • Optional Arguments passed to the executing function
// Every 1000ms, the console prints 1
setInterval(function(){
    console.log(1);
}, 1000);
Copy the code

SetInterval shortcomings

1. Useless calls exist, wasting performance

The timer continues to run in the background, even if the browser is minimized or you switch to another TAB. The call will not stop until the page is closed.

2. Ignore error codes and call them even if they fail

If something goes wrong with the code executed in setInterval, it doesn’t stop running, it just keeps calling.

3. The same invocation interval cannot be guaranteed; A callback may be skipped

Each time setInterval pushes a callback function to an asynchronous queue, it checks whether there is a code instance of the timer in the asynchronous queue. If so, it does not add the callback function.

If the execution of the callback function takes a lot of time to execute, some calls in the middle are ignored.

Example: Analyze the following code execution steps

. some event... setInterval(T, 100); // indicates that T is pushed into the asynchronous queue every 100msCopy the code

  1. The code starts executing, firstsome eventSync code,100msAfter theT1Add to the end of the asynchronous queue;
  2. The main thread is still thereeventThe task is in progress, so it cannot be executed immediatelyT1. This command can be executed only after the main thread task is completeT1;
  3. another100ms.T1Execute on the main threadT2Add to the end of the asynchronous queue becauseT1It’s still being implemented, soT2Can only wait for execution;
  4. another100msAt this point, it should beT3Added to the end of the asynchronous queue, but because the asynchronous queue existsT2, soT3Not added to the queue (skipped).
  5. T1After the command is executed, it is immediately removed from the asynchronous queueT2Execution (T1Attached toT2Execution, and did not achieve the effect of timer)

From the above examples, we can see two disadvantages of setInterval:

  1. In some extreme cases, there is no guarantee that callback functions will run at intervals;
  2. When a callback takes too long to execute, a callback may be ignored.

Use setTimeout instead of setInterval

/** * Use setTimeout to simulate a setInterval timer *@param fn
 * @param delay
 * @param args
 * @returns {{clear: (function(): void)}}
 * @private* /
function _interval(fn, delay, ... args){
    let timerId;

    function callback(){ fn(... args); timerId =setTimeout(callback, delay)
    }

    timerId = setTimeout(callback, delay);
    // Clear the timer method
    return {
        clear:() = > clearTimeout(timerId)
    };
}

// Start timer
const timer  = _interval(function(){
    console.log(1);
}, 1000);

// Clear the timer
setTimeout(timer.clear, 5 * 1000);
Copy the code

setTimeout

SetTimeout Sets a timer that executes a function or a piece of code after the specified time expires.

Key: Timer refers to the delay time after the callback function will be added to the asynchronous queue, the real execution time needs to wait until the main thread is empty and then execute. So the actual execution time >= latency time

parameter

  • function/code
    • Required Function/string to be called repeatedly. Is compiled to when it is a stringjsCode execution.
  • delay
    • Required periodicallyfunction/codeTime interval in milliseconds.
    • Note:HTML5Specifies that the minimum execution interval is4msWhen less than4ms, the default value is4ms.
  • args1... argsN
    • Optional Arguments passed to the executing function
// Add the function to the asynchronous queue after 1000ms and print 1
setTimeout(function(){
    console.log(1);
}, 1000);
Copy the code

SetTimeout shortcomings

1. The execution time cannot be determined

2. Animation may have stutter, frame loss and jitter on some models.

As mentioned in the beginning, the essence of animation is: visual residue caused by naked eyes and dynamic illusion formed by continuously playing static images. We sometimes get stuck because we don’t have enough frame rates.

Although you can set the interval to be synchronized with the refresh frequency of most computers by setting a fixed interval setTimeout(FN, 16.7). But it will still be affected by the following factors:

  • Due to theJS engineThreads are asynchronous,setTimeoutAn asynchronous task can be executed only after the tasks on the main thread are completed. So its callbacks are realStart time >= 16.7ms
  • Different machines refresh at different rates,setTimeoutI can only write one time, not accurate enough

The above situations will cause the interval of setTimeout execution to be out of sync with the browser refresh frequency, resulting in animation stutter, frame loss and jitter.

So is there the ultimate in animation? Let’s introduce the requestAnimationFrameAPI.

requestAnimationFrame(rFA)

We can use CSS3’s animation and transition properties to animate, but CSS3 can’t handle the need to “return the scroll bar to the top at a constant speed.” Because CSS3 cannot control the scrollTop property. This is where the requestAnimationFrame artifact comes in.

Tell the browser window. RequestAnimationFrame () : you want to perform an animation, and require the browser until the next redraw calls the specified callback function to update the animation.

parameter

  • callback
    • Required The function to be executed before the next redraw. This function is passed in by defaultperformanceParameter used to test web page performance.

Use the sample

The following code is called only once after the first browser refresh:

window.requestAnimationFrame(function () {
    console.log(this);  // Print window only once
})
Copy the code

If you want to form a continuous animation, you need to call yourself again in the rAF callback function

To synchronize the call with the browser refresh rate, write:

// Print window continuously
function animateFn (){
    console.log(this);
    window.requestAnimationFrame(animateFn);
}
window.requestAnimationFrame(animateFn);
Copy the code

advantages

1. The execution time is determined by the browser and synchronized with the refresh frequency of the browser, preventing frame loss and delay

Unlike setTImeout and setInterval, the timing of requestAnimationFrame callback calls is not defined by the developer, but by the browser.

  • If the refresh frequency of the machine is60FPS.requestAnimationFrameThe callback function of1/60 ≈ 16.7msLeft and right execution once;
  • If the refresh frequency of the machine is80FPS.requestAnimationFrameThe callback function of1/80 ≈ 12.5msLeft and right execution once;

This mechanism can be synchronized with the browser refresh rate without causing frame loss and lag.

2. Save CPU resources

Unlike setTimeout and setInterval, when a page is minimized or the current TAB is in the “inactive” state, the page refresh task is suspended and the requestAnimationFrame stops rendering to save CPU resources. When a TAB is “activated” again, the requestAnimationFrame continues rendering.

3. High-frequency function throttling

For resize and Scroll events, requestAnimationFrame can be used to ensure that functions are executed only once in each drawing interval, saving the overhead of function execution. If setTimeout and setInterval are used, there may be useless callback function calls in the browser refresh interval, wasting resources.

Cancel rFA cancelAnimation (id)

As with setTimeout and setInterval, requestAnimationFrame returns a unique ID representing the execution, which can be used to cancel rFA.

const id = requestAnimationFrame(function(){});
cancelAnimationFrame(id);
Copy the code

Write a 🌰

Using rFA, click div to start moving to the right, click Stop, and click continue again:

<! doctypehtml>
<html lang="en">
<head>
    <title>Document</title>
    <style>
        .box{
            width: 100px;
            height: 100px;
            background: paleturquoise;
            position: absolute;
            left: 0;
        }
    </style>
</head>
<body>
    <div class="box"/>
    <script src="./index.js"></script>
</body>
</html>
Copy the code
(function (window.document) {
    const oBox = document.getElementsByClassName('box') [0];
    let animationId;

    oBox.addEventListener('click'.function () {
        animationId ? cancelAnimation() : startAnimation(oBox);
    });

    /** * Start exercising *@param Element DOM element */
    function startAnimation(element) {
        element.style.left = parseInt(window.getComputedStyle(element).getPropertyValue("left")) + 1 + 'px';
        animationId = requestAnimationFrame(() = > startAnimation(element))
    }

    /** * Cancel the campaign */
    function cancelAnimation() {
        cancelAnimationFrame(animationId);
        animationId = null;
    }
})(window.document);
Copy the code

Effect:

Write in the last

See here, hope this article is of some help to you 😁. If there are any mistakes in the article, please comment and make progress together ~~~~.

I’m Matcha, learning continuously a coder✌🏻.