前端动画选哪个更好:requestAnimationFrame vs 定时器

摘要:做前端开发时,流畅的动画效果很重要,能明显提升用户体验。但实现动画的方法有很多,到底该选哪种呢?requestAnimationFrame 和定时器(setTimeout、setInterval)都是常用的动画实现方法

做前端开发时,流畅的动画效果很重要,能明显提升用户体验。但实现动画的方法有很多,到底该选哪种呢?requestAnimationFrame 和定时器(setTimeout、setInterval)都是常用的动画实现方法,它们在工作原理、性能表现和使用场景上都有很大不同。


requestAnimationFrame 是什么?

这是浏览器专门为动画提供的接口。它告诉浏览器在下次页面重绘前执行你的动画代码。

基本用法很简单:

let requestId = requestAnimationFrame(callback);
  • callback:浏览器在下次重绘前调用的函数

  • requestId:请求的标识号,可以用来取消动画

工作原理

浏览器运行时有个事件循环机制,处理各种任务。requestAnimationFrame 的回调函数会被放到浏览器的动画帧队列里,在重绘阶段执行。简单说,浏览器每次要更新画面时,会先执行这些动画函数,然后再绘制页面。

优点

  1. 与浏览器刷新同步:动画更新和页面重绘保持同步,避免不必要的重复绘制,性能更好

  2. 智能节能:当页面被隐藏或切到后台时,浏览器会自动暂停动画,节省资源

  3. 动画更流畅:帧率与浏览器刷新率匹配,通常是每秒60帧,动画效果很顺滑

缺点

  1. 兼容性问题:老版本浏览器可能不支持,需要做兼容处理

  2. 不能控制执行频率:执行间隔由浏览器决定,不能像定时器那样精确设置


定时器是什么?

主要通过 setTimeout 和 setInterval 来实现:

  • setTimeout:延迟指定时间后执行一次代码

let timeoutId = setTimeout(function, delay);
  • setInterval:按固定时间间隔重复执行代码

let intervalId = setInterval(function, delay);

工作原理

定时器在设定的时间后把回调函数放入执行队列,等待处理。但由于JavaScript是单线程的,如果当前有任务在执行,定时器的回调可能要等更久才能运行。

优点

  1. 简单好用:用法直观,容易理解

  2. 能控制频率:可以精确设置执行间隔,适合需要固定频率的场景

缺点

  1. 性能问题:如果回调函数执行太久,会阻塞后面代码,影响页面响应

  2. 时间不准:实际执行间隔可能比设定的长,导致动画卡顿

  3. 不会自动优化:即使页面看不见,定时器也会继续执行,浪费资源


两者对比

性能方面

requestAnimationFrame更好,它与浏览器重绘同步,动画流畅,而且在页面不可见时会自动暂停。

定时器可能因为JavaScript执行阻塞导致时间不准,影响动画效果,也没有优化机制。

适用场景

requestAnimationFrame:适合大多数动画场景,特别是需要流畅动画的地方,比如游戏、复杂交互动画。

定时器:适合简单的、对流畅度要求不高的动画,或者需要精确时间控制的非动画任务,比如定期请求数据、倒计时功能。

代码示例对比

用 requestAnimationFrame 实现动画:

let startTime = null;
const element = document.getElementById('box');

function animate(currentTime) {
  if (!startTime) startTime = currentTime;
  const elapsed = currentTime - startTime;
  
  // 假设动画持续2秒
  const progress = Math.min(elapsed / 2000, 1);
  
  element.style.transform = `translateX(${progress * 200}px)`;
  
  if (progress < 1) {
    requestAnimationFrame(animate);
  }
}

requestAnimationFrame(animate);

用 setInterval 实现动画:

const element = document.getElementById('box');
const startTime = Date.now();
const duration = 2000; // 动画持续2秒

const intervalId = setInterval(() => {
  const elapsed = Date.now() - startTime;
  const progress = Math.min(elapsed / duration, 1);
  
  element.style.transform = `translateX(${progress * 200}px)`;
  
  if (progress >= 1) {
    clearInterval(intervalId);
  }
}, 16); // 大约每秒60帧

requestAnimationFrame 的动画更流畅,而且有浏览器优化。setInterval 的动画可能会卡顿。


实际使用建议

  1. 优先选择 requestAnimationFrame
    做动画时首先考虑用它,性能和流畅度都更好。

  2. 处理兼容性问题
    对于不支持 requestAnimationFrame 的老浏览器,可以这样降级:

    window.requestAnimationFrame = window.requestAnimationFrame || 
                                 window.webkitRequestAnimationFrame || 
                                 window.mozRequestAnimationFrame || 
                                 function(callback) {
                                     return setTimeout(callback, 1000 / 60);
                                 };
  3. 避免在动画回调中做复杂操作
    不管是 requestAnimationFrame 还是定时器,在回调函数里都不要做太复杂的计算或DOM操作,否则会影响动画性能。

  4. 及时清理动画
    动画不需要时要用 cancelAnimationFrame 或 clearInterval 及时停止:

    // 对于 requestAnimationFrame
    cancelAnimationFrame(requestId);
    
    // 对于 setInterval
    clearInterval(intervalId);
  5. 控制动画频率
    如果不需要60帧的高频率,可以这样控制:

    let lastTime = 0;
    const fps = 30; // 每秒30帧
    
    function animate(currentTime) {
        if (currentTime - lastTime > 1000 / fps) {
            // 执行动画逻辑
            lastTime = currentTime;
        }
        requestAnimationFrame(animate);
    }


特殊场景考虑

游戏开发
复杂游戏通常用 requestAnimationFrame,但要注意:

  • 不同显示器刷新率可能不同

  • 需要处理帧率波动

  • 可以考虑使用固定时间步长

简单UI动画
比如淡入淡出、滑动效果,直接用 CSS 动画可能更简单,性能也更好。

后台任务
如果是数据同步、定期检查等非动画任务,用 setInterval 更合适。

性能监控
可以监控动画性能,发现问题:

let frameCount = 0;
let lastTime = performance.now();

function checkFPS(currentTime) {
    frameCount++;
    if (currentTime - lastTime >= 1000) {
        console.log('当前FPS:', frameCount);
        frameCount = 0;
        lastTime = currentTime;
    }
    requestAnimationFrame(checkFPS);
}
requestAnimationFrame(checkFPS);


总结

requestAnimationFrame 在大多数动画场景下表现更好,是现代前端动画的首选。但定时器在特定情况下仍然有用。

选择时要考虑:

  • 动画复杂度

  • 性能要求

  • 浏览器兼容性

  • 开发成本

理解两者的区别,能帮你做出合适的选择,做出既好看又流畅的动画效果。记住,好的动画不仅要效果漂亮,还要性能优秀,不给用户设备造成负担。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://shenqiku.cn/article/FLY_13085