本文发表于 194 天前,其中的信息可能已经事过境迁
文章摘要
加载中...|
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结 投诉

性能优化之requestAnimationFrame与requestIdleCallback

requestAnimationFrame

MDN链接:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame

window.requestAnimationFrame() 方法会告诉浏览器你希望执行一个动画。它要求浏览器在下一次重绘之前,调用用户提供的回调函数。

动画实现方式

  • CSS动画
  • JS动画
    • 定时器实现
    • canvas加定时器实现
    • requestAnimationFrame
  • SVG动画

为什么使用requestAnimationFrame

因为使用定时器去做动画,动画会发生抖动

而使用requestAnimationFrame去做动画则不会

为什么使用requestAnimationFrame动画不会卡顿

其实所有的前端性能问题我们都可以在浏览器渲染流程中的某个阶段找到原因,在JS的执行逻辑中,会存在浏览器的时间循环这个机制(大家可以去自行了解一下这个机制,已经很耳熟能详了),而当我们使用定时器去做动画的时候,定时器任务会被放置到计时器队列(属于宏任务队列的一种),属于异步任务,而requestAnimationFrame(下面简称rAF)也同样属于宏任务。

那么定时器的动画区别又和rAF有什么区别呢?

本质上就是在于,当到了每次渲染帧之前rAF的回调函数都会去执行,保证了动画尽可能的在每一帧都会去渲染,之所以说尽可能,那是因为如果回调较为复杂,或者由于事件循环的原因赶不上渲染帧的时候,渲染还是会放到下一帧,所以此时也会产生卡顿。

而使用定时器实现的动画,在浏览器事件循环的过程中,可能事件会慢慢的错乱,因为浏览器的计时器本身就是不精准的,会导致计时越来越不精准,会导致错过大量的渲染帧,或者同一帧变化很大,这也就导致了动画的卡顿或者抖动,而且动画有可能不会在规定时间内完成。

111.gif111.gif

requestIdleCallback

MDN链接:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback

React 的 fiber 架构便是受到了requestIdleCallback的启发。

window.requestIdleCallback() 方法插入一个函数,这个函数将在浏览器空闲时期被调用。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,如动画和输入响应。函数一般会按先进先调用的顺序执行,然而,如果回调函数指定了执行超时时间timeout,则有可能为了在超时前执行函数而打乱执行顺序。

你可以在空闲回调函数中调用 requestIdleCallback(),以便在下一次通过事件循环之前调度另一个回调。

  1. 回调函数: 回调函数是在主线程空闲时被调用的函数。每次调用时,都会传入一个IdleDeadline对象,该对象提供一个timeRemaining()方法,用来检测当前帧中剩余的空闲时间。
  2. 空闲时间和截止时间(deadline) : IdleDeadline对象的timeRemaining()方法返回一个DOMHighResTimeStamp,表示在执行回调函数时,在当前帧中剩余多少空闲时间(毫秒)。开发者可以使用这个时间来执行任务,并在时间耗尽前选择适当的时机终止任务,从而避免影响关键渲染或事件处理。
  3. 调度和取消回调: requestIdleCallback函数安排一个回调函数在主线程下一次空闲时被执行,并返回一个ID,可以用这个ID通过cancelIdleCallback函数取消回调。
  4. 超时: 你还可以给requestIdleCallback传递一个对象,其中一个属性是timeout,用来指定最长时间(毫秒)。如果任务在指定的时间内尚未执行,即使主线程不空闲,浏览器也会尽量执行回调。

new-thread.pngnew-thread.png

适合的场景

  1. 预处理,例如当你需要处理一些数据,但这些数据不需要立即展示给用户时,可以在空闲时预处理这些数据。
  2. 埋点日志相关,对于跟踪和分析网站使用情况的代码,通常可以在空闲时执行,以减少影响用户体验的风险。
  3. 延迟执行: 当你有一些非必须立刻执行的代码时,比如初始化某些非关键的UI组件,你可以使用 requestIdleCallback 来推迟这些任务的执行。

使用requestIdleCallback的目的是确保关键任务(如处理用户输入、动画等)能够不受干扰地顺滑运行,而将非关键任务推迟到浏览器有足够资源处理它们的时候。这样既提高了页面性能,又优化了用户体验。需要注意的是,并不是所有的后台任务都适合用requestIdleCallback来处理;

不适合的场景

  1. 不适合操作dom&更新UI 因为执行时机不确定可能导致视觉难以预测,而且requestIdleCallback是在渲染完成才调用的 可能会引发回流重绘。
  2. 不适合做一些耗时的长任务。虽然是在浏览器空闲执行 但依然运行在主线程上 耗时的长任务同样会导致帧率降低, 造成页面卡顿。

文献参考

本文非原创,只是对下面的文章做总结

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback

https://juejin.cn/post/7190728064458817591

https://juejin.cn/post/7350140783548956683

赞赏博主
评论 隐私政策