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:
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?
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).