请解释 requestAnimationFrame 的作用和优势。它和 setTimeout、setInterval 有什么区别?

推荐答案

requestAnimationFrame 的主要作用是在浏览器下一次重绘之前执行回调函数,它利用浏览器的刷新机制,让动画和更新操作更加平滑高效。

优势:

  • 性能优化: requestAnimationFrame 由浏览器控制执行时机,与屏幕刷新率同步,避免了过度绘制和丢帧,能提供更流畅的动画体验。
  • 节能: 当页面不在激活状态(例如标签页切换到后台)时,requestAnimationFrame 的回调会被暂停,节省 CPU 资源和电量。
  • 精确性:setTimeoutsetInterval 更精确地控制动画帧率,减少因计时误差造成的抖动。

setTimeoutsetInterval 的区别:

特性 requestAnimationFrame setTimeout setInterval
执行时机 浏览器重绘前 指定延迟时间后 指定间隔时间后循环执行
执行频率 与浏览器刷新率同步 由延迟时间决定,可能不准确 由间隔时间决定,可能不准确
性能 高,避免过度绘制 较差,可能造成性能问题 较差,可能造成性能问题
节能 页面隐藏时暂停执行 页面隐藏时仍执行 页面隐藏时仍执行
应用场景 动画、平滑滚动、绘制操作 延迟执行、异步操作 重复执行某操作
精度 更精确 可能存在计时误差 可能存在计时误差

本题详细解读

什么是 requestAnimationFrame

requestAnimationFrame 是一个浏览器提供的 API,它接受一个回调函数作为参数,这个回调函数会在浏览器下一次重绘之前执行。其核心机制是与浏览器的刷新率同步,通常来说,显示器刷新率是 60Hz 或更高,这意味着浏览器每秒会进行 60 次或者更高频率的重绘,以更新屏幕显示内容。requestAnimationFrame 会将你的动画逻辑绑定到这个重绘过程,确保动画的更新和屏幕的刷新同步,从而带来更流畅的视觉体验。

requestAnimationFrame 的工作原理

  1. 调度: 当你调用 requestAnimationFrame 并传入一个回调函数时,浏览器会将这个回调函数加入到一个待执行队列中。
  2. 同步: 在每一次屏幕刷新周期即将开始时,浏览器会检查这个队列,如果队列中有待执行的回调函数,那么会依次执行这些回调。
  3. 重绘: 执行完回调后,浏览器会进行页面的重绘,将新的内容展示在屏幕上。

这个过程是循环进行的,直到你取消了 requestAnimationFrame 的回调,或者浏览器停止了页面的渲染。

setTimeoutsetInterval 的不足

  • 计时误差: setTimeoutsetInterval 的执行时间并非完全精确,受到浏览器线程调度和其他因素的影响,实际执行时间可能与设置的时间有偏差。
  • 过度绘制和丢帧: 如果 setTimeoutsetInterval 设置的时间间隔小于浏览器的刷新时间,可能会导致过度绘制,浏览器会重复渲染没有变化的页面内容,浪费资源;反之,如果时间间隔过大,可能会导致动画丢帧,动画效果不流畅。
  • 页面隐藏时的浪费: 即使页面不可见,例如切换了标签页或者窗口最小化,setTimeoutsetInterval 依然会继续执行,浪费资源。

requestAnimationFrame 的优势详细分析

  1. 流畅的动画: requestAnimationFrame 与浏览器的刷新率同步,可以避免因计时误差造成的动画抖动,提供更平滑的动画体验。当动画更新逻辑与帧率保持一致时,可以实现最佳的用户体验。
  2. 资源优化: 浏览器会控制 requestAnimationFrame 的执行时机,在不激活的标签页或者窗口中,它会自动暂停回调,从而节省 CPU 资源和电量。
  3. 防止过度绘制和丢帧: 由于回调函数在每次浏览器重绘之前执行,所以不会出现过度绘制和丢帧的情况。只有当页面需要更新时,回调函数才会执行。
  4. 精确性: requestAnimationFrame 提供的执行时机是精确的,因为它是浏览器渲染的一部分。

应用场景

  • 动画效果: 各种类型的动画效果,例如元素移动、淡入淡出、缩放等。
  • 平滑滚动: 实现平滑的页面滚动效果,特别是自定义滚动条的场景。
  • 绘制操作: 使用 canvas 绘制图形、动画或者游戏。
  • 性能优化: 需要精准控制执行时机的任何场景,都可以考虑使用 requestAnimationFrame, 例如在游戏开发中。
  • DOM 更新: 当需要频繁更新 DOM 时,使用 requestAnimationFrame 可以将多次更新合并为一次,提高性能。

使用示例

-- -------------------- ---- -------
-------- ---------------- --------------- -
  --- ------------- - -------------------
  --- --------- - -----

  -------- --------------- -
    -- ------------ --------- - ----------
    ----- -------- - ---------- - ---------- - ----- -- -------
    ----- -------- - -------------- - --------------

    -- --------- - -- -
      ------------------ - ------------- - -------- - -------- - -----
       ----------------------------
    -
     ---- -
      ------------------ - -------------- - -----
    -
  -
  ----------------------------
-


----- --------- - -------------------------------------
----- -------------- - ----
------------------ ----------------

这个示例演示了使用 requestAnimationFrame 实现一个简单的元素移动动画,它会从当前位置平滑移动到目标位置。

纠错
反馈