代码优化: requestAnimationFrame来代替setTimeout

3 篇文章 0 订阅
2 篇文章 0 订阅

最近看antdv 某些组件源码的时候发现,是使用requestAnimationFrame 来代替 setTimeout;下面我们就来看看是如何实现的;

首先 requestAnimationFrame与setTimeout相比,requestAnimationFrame 最大的优势是由浏览器来决定回调函数的执行时机,即紧跟浏览器的刷新步调。

其次,CPU节能:使用setTimeout实现的动画,当页面被隐藏(隐藏的)或最小化(后台标签页)时,setTimeout仍然在后台执行动画任务(只不过执行时间有所延迟),由于此时页面处于不可见或不可用状态,刷新动画是没有意义的,而且还浪费 CPU 资源和电池寿命。而requestAnimationFrame则完全不同,当页面处于未激活的状态下,该页面的屏幕绘制任务也会被浏览器暂停,因此跟着浏览器步伐走的requestAnimationFrame也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了 CPU 开销,提升性能和电池寿命。

// getRequestAnimationFrame.js
// 判断是否支持 requestAnimationFrame/cancelAnimationFrame |setTimeout/clearTimeout,根据支持语法返回对应的方法

const availablePrefixs = ['moz', 'ms', 'webkit']

function requestAnimationFramePolyfill () {
  let lastTime = 0
  return function (callback) {
    const currTime = new Date().getTime()
    const timeToCall = Math.max(0, 16 - (currTime - lastTime))
    const id = window.setTimeout(function () {
      callback(currTime + timeToCall)
    }, timeToCall)
    lastTime = currTime + timeToCall
    return id
  }
}

export default function getRequestAnimationFrame () {
  if (typeof window === 'undefined') {
    return () => {}
  }
  if (window.requestAnimationFrame) {
    // https://github.com/vuejs/vue/issues/4465
    return window.requestAnimationFrame.bind(window)
  }

  const prefix = availablePrefixs.filter(key => `${key}RequestAnimationFrame` in window)[0]

  return prefix ? window[`${prefix}RequestAnimationFrame`] : requestAnimationFramePolyfill()
}

export function cancelRequestAnimationFrame (id) {
  if (typeof window === 'undefined') {
    return null
  }
  if (window.cancelAnimationFrame) {
    return window.cancelAnimationFrame(id)
  }
  const prefix = availablePrefixs.filter(
    key => `${key}CancelAnimationFrame` in window || `${key}CancelRequestAnimationFrame` in window
  )[0]

  return prefix
    ? (
      window[`${prefix}CancelAnimationFrame`] || window[`${prefix}CancelRequestAnimationFrame`]
    ).call(this, id)
    : clearTimeout(id)
}

// requestAnimationTimeout.js
// 创建自定 方法 requestAnimationTimeout 用于延迟执行
// 创建自定 方法 cancelAnimationTimeout 用于清除还未执行的requestAnimationTimeout
import getRequestAnimationFrame, {
  cancelRequestAnimationFrame
} from './getRequestAnimationFrame'

const dataSetTimeout = getRequestAnimationFrame()

export const cancelAnimationTimeout = frame => cancelRequestAnimationFrame(frame.id)

export const requestAnimationTimeout = (callback, delay = 0) => {
  const start = Date.now()
  function timeout () {
    if (Date.now() - start >= delay) {
      callback.call()
    } else {
      obj.id = dataSetTimeout(timeout)
    }
  }

  const obj = {
    id: dataSetTimeout(timeout)
  }

  return obj
}

使用就直接引入 requestAnimationTimeout.js 导出其 {requestAnimationTimeout, cancelAnimationTimeout } 方法;

requestAnimationTimeout 方法会返回一个 object 对象, 包含一个id值;如果需要取消执行,cancelAnimationTimeout(/* 将 requestAnimationTimeout 方法会返回一个 object 对象,作为参数*/);

希望能对你有帮助!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在你的代码中出现了"ReferenceError: requestAnimationFrame is not defined"的错误。这个错误通常是由于浏览器不支持requestAnimationFrame函数引起的。为了解决这个问题,你可以在main.js文件中添加一个requestAnimationFrame的polyfill函数来模拟这个函数的行为。你可以使用下面的代码片段来添加这个polyfill函数: (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for (var x = 0; x < vendors.length && !window.requestAnimationFrame; x++) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; } if (!window.cancelAnimationFrame) { window.cancelAnimationFrame = function(id) { clearTimeout(id); }; } })(); 通过添加这个polyfill函数,你可以确保在不支持requestAnimationFrame函数的浏览器上也能正常运行你的代码。希望这能解决你的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [vue项目在IE9下报错 “requestAnimationFrame”未定义](https://blog.csdn.net/anmi7832/article/details/102031323)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Python 解决execjs._exceptions.ProgramError: ReferenceError: document is not defined报错问题](https://download.csdn.net/download/weixin_38508126/14888148)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [初识React项目遇到的坑(Uncaught ReferenceError: Set is not defined )](https://blog.csdn.net/vv_bug/article/details/82888476)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值