在浏览器 API 中,我们有一种方法通过递归调用
requestAnimationFrame
来测量两帧之间的距离。但是,如果我们在页面加载之前开始收集所有 requestAnimationFrame
调用,我们可以提到,有时在慢速网页上,帧速率超过 50 + Frame Rate
。
50
是一个间隔 我们可以在长任务期间延迟。
然后我们可以将真实的 Chrome 长任务(通过观察 PerformanceLongTaskEntries)与递归执行进行比较
requestAnimationFrame
,发现它们是不同的。
有脚本可以对比:
<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>
在这里,在 StackOverflow 网页上,我在页面加载时运行此脚本:
并且两种方法的持续时间和条目数不同。我的问题是 为什么两帧之间的较长间隔不能产生长任务?
rAF 间隔可能由许多短任务而不是一个长任务组成。
长任务也不包括渲染阶段(包括 rAF 回调本身)。
长动画帧 API (LoAF) 专门设计用于解决 这些缺点。
如果您使用该 API 重复测试,我很有兴趣查看结果。您需要在 chrome://flags
中启用
实验性 Web 平台功能,然后才能默认启用它(目前计划在 Chrome 123 中启用)。