最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Confusion about frame drops and requestAnimationFrame - Stack Overflow

programmeradmin1浏览0评论

Please free feel to point out if my following understanding is wrong: Assume our display refresh rate is 60hz (I know it is not always the case but let's just assume it is 60hz) so the web page would refresh the screen 60 times every second if everything goes well. That means the rendering is happening at 16 ms interval (roughly) right? So anything in our JavaScript that takes more than 16 ms to execute would cause janky experience to the user. So my question is:

  1. let's say we have a function handleScroll and it is going to take 100ms to execute from start to finish. and we added it to addEventListener('scroll', handleScroll). Is it true that whenever scroll event fires, the user would experience jank experience since 6 frames are skipped/dropped in the rendering cycle? because 100ms / 16ms = 6.25? I know a task takes long time on main thread it will stop all other task until its done, but here I wanted to get some quantitative analysis or methodologies for qualitative analysis for such a performance issue. specifically I wanted to understand (roughly )how many frames are going to get dropped with such a callback (if the refresh rate is 60hz)
  2. I think requestAnimationFrame tells the browser to run the callback before the next frame is rendered so I saw people mentioned that it can prevent frames being dropped for animation. But it is unclear to me how it is going to help with that since the callback we pass into requestAnimationFrame is still going to run to pletion so if that callback takes more than 16ms we are going to miss the next frame inevitably right?

Please free feel to point out if my following understanding is wrong: Assume our display refresh rate is 60hz (I know it is not always the case but let's just assume it is 60hz) so the web page would refresh the screen 60 times every second if everything goes well. That means the rendering is happening at 16 ms interval (roughly) right? So anything in our JavaScript that takes more than 16 ms to execute would cause janky experience to the user. So my question is:

  1. let's say we have a function handleScroll and it is going to take 100ms to execute from start to finish. and we added it to addEventListener('scroll', handleScroll). Is it true that whenever scroll event fires, the user would experience jank experience since 6 frames are skipped/dropped in the rendering cycle? because 100ms / 16ms = 6.25? I know a task takes long time on main thread it will stop all other task until its done, but here I wanted to get some quantitative analysis or methodologies for qualitative analysis for such a performance issue. specifically I wanted to understand (roughly )how many frames are going to get dropped with such a callback (if the refresh rate is 60hz)
  2. I think requestAnimationFrame tells the browser to run the callback before the next frame is rendered so I saw people mentioned that it can prevent frames being dropped for animation. But it is unclear to me how it is going to help with that since the callback we pass into requestAnimationFrame is still going to run to pletion so if that callback takes more than 16ms we are going to miss the next frame inevitably right?
Share Improve this question edited Sep 9, 2021 at 19:21 Joji asked Sep 6, 2021 at 18:34 JojiJoji 5,67611 gold badges58 silver badges117 bronze badges 1
  • 1 What problem do you want to solve? You didn't ask a specific question. Based on your ments you seem to be interested mainly in calculating a hypothetical drop rate. Which for one you have done in your question text and which is something that will always be hypothetical. In practice, you would just measure it. So what exactly do you want to achieve? – a better oliver Commented Sep 10, 2021 at 12:55
Add a ment  | 

2 Answers 2

Reset to default 5 +75
  1. yes, in that case you would be firing handleScroll at far less than 60 fps - depending on what your handleScroll callback is doing, your users may experience some jank.

  2. requestAnimationFrame will do its best to maintain 60fps, but does not guarantee 60fps. It can potentially run much slower depending on available CPU, GPU, memory, and other limitations.

Note that even when it does run at >60fps, that gives you (as you pointed out) a frame budget of 16-17ms in which to perform your callback actions.

So if your callback takes 100ms to execute, then you are not going to get a smooth 60fps animation even using requestAnimationFrame. Chrome's performance dev tools can help you identify what is causing the lag in your animations, but it is up to you to optimize your callback to run in less than 17ms in order to prevent dropping frames.

Check out this article for a more in depth breakdown

There are two caveats in your assumptions, first is that you have 16ms budget (on 60 hertz) to spend which is not correct since browser has do some sort of internal calculation to draw next frame which takes quite some time around 6ms on chrome thus we have about ~10ms as explained here

Second assumption is that devices will have 60hz refresh rate, which is going to outdated in near future as more devices using high refresh rates to improve scroll smoothness, or even reducing the refresh rate to save battery; so those are not safe assumptions.

By the way generally the principle is the same, if a task takes long time on main thread it will stop all other task until its done, lets demonstrate it in action:

lag function simulates a cpu-intesive task that take a while to run; raf function will move the 200px by scheduling a recursive requestAnimationFrame to itself which will change translateX property of the box; and finally we have a laggyRaf which uses lag function to simulate a long task;

const box = document.querySelector('.box');
const x_move_distance = 200;

function lag (delay = 1000) {
  const time = Date.now();
  while ( Date.now() < time + delay ) {
    // waits 
  }
}

function moveBox ( position ) {
  box.style.transform = `translateX(${position}px)`;
}

let counter = 0;
function raf() {
  moveBox(counter);
  if ( counter < x_move_distance ) {
    requestAnimationFrame(raf);
    counter++;
  }
}

let counter2 = 0;
function laggyRaf() {
  moveBox(counter2);
  lag(100); //100 ms seconds extra lag
  if ( counter2 < x_move_distance ) {
    requestAnimationFrame(laggyRaf);
    counter2++;
  }
}
.box {
  width: 100px;
  height: 100px;
  background: blue;
}
<div class='box'></div>
<button onclick="counter = 0; raf()">start raf animations</button>
<button onclick="lag()">start cpu-intensive task</button>
<br />
<button onclick="counter2 = 0; laggyRaf()">start laggy animations</button>

发布评论

评论列表(0)

  1. 暂无评论