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 to
1s
Number of internal screen refreshes. - The average computer’s screen refresh rate is zero
1 s 60 times
(1000ms / 60 ≈ 16.7ms
|60FPS
), that is, each16.7 ms
It refreshes the screen. Of course, this number depends on resolution, graphics card, screen size, and other factors. - Because the average computer refresh rate is
60FPS
, 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 string
js
Code execution.
- Required Function/string to be called repeatedly. Is compiled to when it is a string
delay
- Required periodically
function/code
Time interval in milliseconds. - Note:
HTML5
Specifies that the minimum execution interval is10ms
When less than10ms
, the default value is10ms
.
- Required periodically
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
- The code starts executing, first
some event
Sync code,100ms
After theT1
Add to the end of the asynchronous queue; - The main thread is still there
event
The task is in progress, so it cannot be executed immediatelyT1
. This command can be executed only after the main thread task is completeT1
; - another
100ms
.T1
Execute on the main threadT2
Add to the end of the asynchronous queue becauseT1
It’s still being implemented, soT2
Can only wait for execution; - another
100ms
At this point, it should beT3
Added to the end of the asynchronous queue, but because the asynchronous queue existsT2
, soT3
Not added to the queue (skipped). T1
After the command is executed, it is immediately removed from the asynchronous queueT2
Execution (T1
Attached toT2
Execution, and did not achieve the effect of timer)
From the above examples, we can see two disadvantages of setInterval:
- In some extreme cases, there is no guarantee that callback functions will run at intervals;
- 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 string
js
Code execution.
- Required Function/string to be called repeatedly. Is compiled to when it is a string
delay
- Required periodically
function/code
Time interval in milliseconds. - Note:
HTML5
Specifies that the minimum execution interval is4ms
When less than4ms
, the default value is4ms
.
- Required periodically
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 the
JS engine
Threads are asynchronous,setTimeout
An 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,
setTimeout
I 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 default
performance
Parameter used to test web page performance.
- Required The function to be executed before the next redraw. This function is passed in by default
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 is
60FPS
.requestAnimationFrame
The callback function of1/60 ≈ 16.7ms
Left and right execution once; - If the refresh frequency of the machine is
80FPS
.requestAnimationFrame
The callback function of1/80 ≈ 12.5ms
Left 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✌🏻.