This is the 19th day of my participation in the August Challenge. Check out the August Challenge for more details

preface

Last time we looked at setTimeout and setInterval and got a little bit of an understanding of that, what is requestAnimationFrame? Why is there a requestAnimationFrame? Today we’re going to analyze it. Let’s get started.

Html5 provides an API dedicated to request animation, requestAnimationFrame, which is literally “requestAnimationFrame”. To fully understand the principles behind requestAnimationFrame, we first need to look at a few concepts related to it:

Screen rendering frequency

The rate at which an image is updated on the screen, or the number of times an image appears on the screen per second, is measured in Hertz (Hz). For a normal laptop, this frequency is about 60Hz, which can be viewed and set by right-clicking on the desktop > screen resolution > advanced Settings > monitor. This value depends on the screen resolution, screen size, and graphics card. In principle, it can be set to a comfortable value for the eyes.

There are two kinds of monitors commonly used in the market, namely, CRT and LCD. CRT is a Cathode Ray Tube and LCD is Liquid Crystal Display.

CRT is a display that uses a cathode ray tube. The graphic images on the screen are composed of fluorescent points that emit light due to the impact of an electron beam. As the phosphor in the CRT has a short luminous time after being hit by an electron beam, the electron beam must continuously hit the phosphor to make it continue to emit light. The number of times the electron beam hits the phosphor per second is the screen rendering frequency.

For LCDS, however, there is no problem with drawing frequency, because each pixel in the LCD continues to glow until the non-glowing voltage changes and is sent to the controller, so the LCD does not have the flicker caused by the electron beam hitting the phosphor.

As a result, the computer screen is constantly updating the image 60 times per second, even when you’re looking at it and doing nothing. Why don’t you feel this change? That is because people’s eyes have visual retention effect, that is, the impression of the previous picture in the brain has not disappeared, followed by the next picture followed by the middle of the 16.7ms interval (1000/60≈16.7), so you will mistakenly think that the image on the screen is still. The screen is right. If the refresh rate is 1 refresh per second, the image on the screen will flicker severely, which can easily cause eye strain, soreness and dizziness.

Principles of CSS Animation

According to the principle above, what you’re seeing is an image being drawn 60 times per second, so high that you can’t feel it being drawn. The essence of animation is to let the human eye see the visual effect of the changes caused by the drawing of the image, and this change should be carried out in a coherent and smooth way. So how do you do that?

A 60Hz screen is drawn every 16.7ms. If you move the position of the elements to the left one pixel, i.e., 1px, before each screen is drawn, you will see the image moving by 1px each time the screen is drawn. And because of the visual stop effect, the image stays in the brain in the current position, and then the image is moved to the next position, so you see the effect that the image is moving smoothly. This is the visual animation.

RequestAnimationFrame principle

Because setTimeout and setInterval are asynchronous apis, they must wait for the synchronous task to execute and for the microtask to complete before executing the current callback function.

There’s a problem here, there’s no way to pinpoint time, even if you write it as 16, there’s no way to pinpoint time to 16. The time interval is not guaranteed.

The biggest advantage of requestAnimationFrame over setTimeout is that the system decides when to execute the callback function.

If the system draw rate is 60Hz, then the callback function is executed every 16.7ms. If the draw frequency is 75 hz, then the interval becomes 1000/75=13.3ms, that is, its time interval follows the system draw frequency.

It ensures that the callback function is executed only once during each screen draw interval, so that frames are not lost and animations don’t get stuck.

RequestAnimationFrame usage

The use of setTimeout is exactly the same as setTimeout, except that the current interval follows the system’s drawing frequency and is fixed.

CancelAnimationFrame (timer1) cancelAnimationFrame(timer1)

// Call the system interval
var timer1 = requestAnimationFrame(function() {
  console.log(1);
});
var timer2 = requestAnimationFrame(function() {
  console.log(2);
});
var timer3 = requestAnimationFrame(function() {
  console.log(3);
});

cancelAnimationFrame(timer1);
Copy the code

RequestAnimationFrame compatibility processing

The main compatibility handling here is to use setTimeout instead when requestAnimationFrame is not supported.

if (!window.requestAnimationFrame) {
  requestAnimationFrame = function(fn) {
    setTimeout(fn, 17);
  };
}
Copy the code

Write an example to familiarize yourself

Requirement: Click the button to display the progress bar effect picture:

The HTML code

<div id="test" style="width: 0px; height: 12px; line-height: 12px; margin-bottom: 5px; background: rgb(185, 236, 243);"></div>Current Progress:<span id="progress">0%</span>
<button id="btn">Enable the progress bar</button>
Copy the code

Use setInterval

btn.onclick = function() {
  var timer = setInterval(function () {
    if (parseInt(test.style.width) < 300) {
      test.style.width = parseInt(test.style.width) + 3 + 'px';
      progress.innerHTML = parseInt(test.style.width) / 3 + The '%';
    } else {
      clearInterval(timer); }},17);
}
Copy the code

Use setTimeout

btn.onclick = function() {
  var timer = setTimeout(function fn() {
    if (parseInt(test.style.width) < 300) {
      test.style.width = parseInt(test.style.width) + 3 + 'px';
      progress.innerHTML = parseInt(test.style.width) / 3 + The '%';
      timer = setTimeout(fn, 17);
    } else {
      clearTimeout(timer); }},17);
}
Copy the code

Use the requestAnimationFrame implementation

btn.onclick = function() {
  var timer = requestAnimationFrame(function fn() {
    if (parseInt(test.style.width) < 300) {
      test.style.width = parseInt(test.style.width) + 3 + 'px';
      progress.innerHTML = parseInt(test.style.width) / 3 + The '%';
      timer = requestAnimationFrame(fn);
    } else{ cancelAnimationFrame(timer); }}); }Copy the code

reference

  • What problem does H5’s new artifact — requestAnimationFrame solve? The front end must be the core
  • How much does requestAnimationFrame know?
  • RequestAnimationFrame principle and compatibility encapsulation

Wrote last

RequestAnimationFrame is essentially a solution to the problem of timer interval instability.

If there are any mistakes in this article, please correct them in the comments section. If this article helped you or you liked it, please like it and follow it.