javascriptperformancegoogle-chromerequestanimationframeweb-performance

Why long frame intervals do not the same as long tasks?


In browser API, we can measure the distance between two frames by calling requestAnimationFrame recursively. If we start to collect all requestAnimationFrame calls while the page is loading, we can mention that sometimes on slow web pages, the distance between frames is more than 50ms + Frame Rate.

50ms is a minimal interval for long task.

Then we can compare real Chrome long tasks (by observing PerformanceLongTaskEntries) with durations between recursive executions of requestAnimationFrame and find out that they are different.

There is a script to compare:

<script>
const performanceApiLongTasks = [];
const recursiveRAFIntervals = [];

function recursiveRAF(callback) {
  let abort = false;

  let fn;
  fn = () => {
    requestAnimationFrame(() => {
      if (!abort) {
        callback();
        requestAnimationFrame(fn);
      }
    });
  }
  fn();

  return () => { abort = true; };
}

let prevFrameTime = performance.now();
const stopRaf = recursiveRAF(() => {
  const startTime = performance.now(); 

  recursiveRAFIntervals.push({
    startTime,
    duration: startTime - prevFrameTime,
  });

  prevFrameTime = startTime;
});

const observer = new PerformanceObserver(list => {
  list.getEntriesByType('longtask').forEach(entry => {
    performanceApiLongTasks.push(entry);
  });
});
observer.observe({type: 'longtask', buffered: true});

setTimeout(() => {
  stopRaf();
  observer.disconnect();

  compare();
}, 10_000);

function compare() {
  const frameRate = Math.min(...recursiveRAFIntervals.map(({duration}) => duration));
  console.log({
    performanceApiLongTasks,
    recursiveRAFIntervals,
    rafIntervals: recursiveRAFIntervals.filter(({duration}) => duration > 50 + frameRate),
    frameRate,
  });
}
</script>

Here, on the StackOverflow web page, I run this script on page load:

enter image description here

The duration and entry count of the two methods are different. My question is why a long interval between two frames does not produce a long task?


Solution

  • A rAF interval may be made up of lots of short tasks rather than one long task.

    Long tasks also do not include the rendering phase (including the rAF callbacks themselves).

    The Long Animation Frames API (LoAF) has been specifically designed to address these shortcomings.

    I’d be interested to see the results if you repeating your tests with that API. You’ll need to enable experimental web platform features in chrome://flags to enable that before it becomes enabled by default (currently scheduled for Chrome 123).