封装 requestAnimationFrame 来代替 setTimeout

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

最近看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 对象,作为参数*/);

希望能对你有帮助!

今天的文章封装 requestAnimationFrame 来代替 setTimeout分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19929.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注