2025-02-03
编程与技术
00
请注意,本文编写于 88 天前,最后修改于 88 天前,其中某些信息可能已经过时。

目录

前言
为什么不要再依赖setTimeout?
1. 延时不精准
2. 帧率和性能问题
3. 后台标签页依然消耗资源
requestAnimationFrame —— 动画和DOM更新的最佳拍档
工作原理
常见应用场景
1. 平滑动画与交互效果
2. 页面滚动和视差效果
3. Canvas 动画和游戏开发
4. 数据可视化与实时图表
总结

前言

在前端开发中,我们经常需要在页面刷新、动画执行或 DOM 更新完成后执行某些操作。许多开发者习惯使用 setTimeout 来延迟执行代码,试图等待浏览器完成渲染。但这种方式不仅不够精准,还可能导致性能问题和用户体验下降。今天,我们就来深入了解一下浏览器专门为动画和渲染优化提供的 API —— requestAnimationFrame,以及它在各种场景中的应用。

为什么不要再依赖setTimeout?

1. 延时不精准

使用 setTimeout 固定延时,通常我们会设置一个类似 100ms16ms 的延时,但浏览器的渲染和重绘并不是严格按照这个时间间隔执行的。延时设置过长,用户会感到操作迟缓;延时设置过短,则可能还没等到 DOM 更新完毕,代码就开始执行,导致意外错误。

2. 帧率和性能问题

setTimeout 无法保证与浏览器的刷新率同步。例如,在动画执行过程中,如果浏览器刷新率为 60Hz,理想情况下每帧更新应该在 16.67ms 左右。使用 setTimeout 可能会错过理想的帧率,导致动画跳帧或不流畅,甚至浪费 CPU 资源。

3. 后台标签页依然消耗资源

当页面处于后台时,setTimeout 仍然会按照设定的时间间隔运行,而浏览器可能会暂停某些动画和渲染操作。此时,代码与用户看不见的页面状态不同步,容易产生不必要的性能浪费。

requestAnimationFrame —— 动画和DOM更新的最佳拍档

requestAnimationFrame 是浏览器为实现流畅动画和高效 DOM 更新而设计的 API。它会在浏览器下一次重绘前执行指定的回调函数,确保代码执行时正好赶上页面渲染的最佳时机。

工作原理

  • 与浏览器刷新同步 当你调用 requestAnimationFrame(callback) 时,浏览器会在下次重绘前调用 callback。通常,显示器的刷新率是 60Hz,也就是每秒 60 帧,这样每帧大约 16.67ms。
  • 自动优化 如果页面处于后台,浏览器会自动暂停 requestAnimationFrame 的回调,这样可以降低 CPU 使用率,节省电池能耗。
  • 高精度时间戳 回调函数会自动传入一个高精度的时间戳,开发者可以利用它计算动画进度,实现精准的动画效果。

常见应用场景

1. 平滑动画与交互效果

对于元素移动、缩放、渐变等动画效果,使用 requestAnimationFrame 可以确保每一帧都与浏览器的重绘周期同步,动画更流畅、更自然。 例如,下面的代码展示了如何用 requestAnimationFrame 实现一个简单的平移动画:

javascript
function animate(timestamp) { // 根据传入的时间戳计算动画进度 const progress = timestamp - startTime; element.style.transform = `translateX(${Math.min(progress / 10, 200)}px)`; // 当动画还未结束时继续下一帧动画 if (progress < 2000) { requestAnimationFrame(animate); } } const startTime = performance.now(); requestAnimationFrame(animate);

2. 页面滚动和视差效果

在需要根据用户滚动实时更新页面内容或实现视差效果时,使用 requestAnimationFrame 能够保证滚动事件与渲染同步,从而提升页面流畅性。例如:

javascript
let ticking = false; window.addEventListener('scroll', () => { if (!ticking) { requestAnimationFrame(() => { updateParallaxEffect(); // 根据滚动位置更新页面元素 ticking = false; }); ticking = true; } });

3. Canvas 动画和游戏开发

在使用 Canvas 绘制动画或开发小游戏时,每一帧的更新都至关重要。requestAnimationFrame 不仅可以确保动画的流畅性,还能根据浏览器实际刷新频率自动调整动画步伐。例如:

javascript
function gameLoop(timestamp) { ctx.clearRect(0, 0, canvas.width, canvas.height); updateGameState(timestamp); renderGame(ctx); requestAnimationFrame(gameLoop); } requestAnimationFrame(gameLoop);

4. 数据可视化与实时图表

实时更新图表、股票行情、网络流量监控等数据可视化场景中,使用 requestAnimationFrame 可以确保图表更新与页面刷新同步,避免因延时问题导致的数据展示不连贯问题。

总结

在现代前端开发中,不再建议使用 setTimeout 来等待页面渲染或动画更新完成。相比之下,requestAnimationFrame 更加高效、精准,并且能自动与浏览器的渲染周期保持同步。无论你是在制作平滑的动画、处理滚动视差效果,还是在开发 Canvas 游戏和实时数据可视化项目,requestAnimationFrame 都能为你带来更好的用户体验和性能表现。

下次当你需要等待 DOM 更新或执行动画时,试试用 requestAnimationFrame,让页面刷新更智能、更流畅吧!

本文作者:DingDangDog

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!