我的编程空间,编程开发者的网络收藏夹
学习永远不晚

requestAnimationFrame定时动画屏幕刷新率节流的方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

requestAnimationFrame定时动画屏幕刷新率节流的方法

这篇文章主要介绍“requestAnimationFrame定时动画屏幕刷新率节流的方法”,在日常操作中,相信很多人在requestAnimationFrame定时动画屏幕刷新率节流的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”requestAnimationFrame定时动画屏幕刷新率节流的方法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

早期定时动画

以前,在 JavaScript 中创建动画基本上就是使用 setInterval() 来控制动画的执行:

(function () {  function updateAnimations() {    doAnimation1();    doAnimation2();    // ...  }  setInterval(updateAnimations, 100);})();

这种定时动画的问题在于,无法准确知晓循环之间的延时。

无论是 setInterval() 还是 setTimeout(),都是不能保证时间精度的。作为第二个参数的延时只能保证何时会把代码添加到浏览器的任务队列,并不能保证添加到队列就会立即执行。如果队列前面还有其他任务,那么就要等这些任务执行完再执行。

简单来讲,这里的毫秒延时不是指何时这些代码会执行,而是指到时候会把回调添加到任务队列。如果添加到队列后,主线程还被其他任务占用,那么回调就不会立即执行。

知道何时绘制下一帧是创造平滑动画的关键,所以 setInterval()setTimeout() 的不精确是个大问题。

浏览器自身计时器的精度让这个问题雪上加霜。浏览器计时器的精度不足毫秒,最厉害的 Chrome 计时器精度为 4ms。更麻烦的是,浏览器又开始对切换到后台或不活跃的标签页中的计时器执行限流,因此即使将时间间隔设为最优,也免不了只能得到近似的结果。

屏幕刷新率

一般计算机显示器的屏幕刷新率都是 60HZ,基本上意味着每秒需要重绘 60 次。大多数浏览器会限制重绘频率,使其不超过屏幕的刷新率,因为超过屏幕刷新率用户也感知不到。

所以,实现平滑动画最佳的重绘时间间隔为 1000ms/60,大约 17 ms。以这个速度重绘可以实现最平滑的动画,因为这已经是浏览器的极限了。

requestAnimationFrame

requestAnimationFrame() 这个方法可以通知浏览器某些 JavaScript 代码要执行动画了,这样浏览器就可以在运行某些代码后进行适当的优化。

requestAnimationFrame() 这个方法接收一个参数,该参数是一个要在重绘屏幕前调用的函数。这个函数就是修改 DOM 样式以反映下一次重绘有什么变化的地方。为了实现动画循环,可以把多个 requestAnimationFrame() 调用串联起来,就像以前使用 setTimeout() 一样:

function updateProgress() {  var div = document.getElementById("status");  div.style.width = parseInt(div.style.width, 10) + 5 + "%";  if (div.style.left != "100%") {    requestAnimationFrame(updateProgress);  }}requestAnimationFrame(updateProgress);

因为 requestAnimationFrame() 只会调用一次传入的函数,所以每次更新用户界面时需要再手动调用它一次。同时,也需要控制动画何时停止。结果就会得到非常平滑的动画。

requestAnimationFrame() 已经解决了浏览器不知道 JavaScript 动画何时开始的问题,以及最佳间隔时间是多少的问题。但是,如果我们想知道自己的代码实际的执行时间呢?同样有解决方案。

传给 requestAnimationFrame() 的函数实际上可以接收一个参数,该参数表示下次重绘的时间。这一点非常重要:requestAnimationFrame() 实际上把重绘任务安排在了未来一个已知的时间点上,而且通过这个参数告诉了开发者,那么基于这个参数,就可以更好地决定如何调优动画了:

function foo(t) {  console.log(t);  requestAnimationFrame(foo);}requestAnimationFrame(foo);

cancelAnimationFrame

const requestID = window.requestAnimationFrame((t) => {  console.log(t);});window.cancelAnimationFrame(requestID);

通过 requestAnimationFrame 节流

支持这个方法的浏览器实际上会暴露出作为钩子的回调队列。所谓钩子,就是浏览器在执行下一次重绘之前的一个点。这个回调队列是一个可修改的函数列表,包含应该在重绘之前调用的函数。每次调用 requestAnimationFrame() 都会在队列上推入一个回调函数,队列的长度没有限制。

这个回调队列的行为不一定跟动画有关。通过 requestAnimationFrame() 递归地向队列中加入回调函数,可以保证每次重绘最多只调用一次回调函数,这是一个非常好的节流工具。在频繁执行影响页面外观的代码时(比如滚动事件监听器),可以利用这个回调队列进行节流。

先看一个原生实现,其中的滚动事件监听器每次触发都会调用名为 expensiveOperation()(耗时操作) 的函数。当向下滚动网页时,这个事件很快就会被触发并执行成百上千次:

function expensiveOperation() {  console.log("Invoked at", Date.now());}window.addEventListener("scroll", () => {  expensiveOperation();});

如果想把事件处理程序的调用限制在每次重绘之前,那么就可以把它封装到 requestAnimationFrame() 调用中:

function expensiveOperation() {  console.log("Invoked at", Date.now());}window.addEventListener("scroll", () => {  window.requestAnimationFrame(expensiveOperation);});

这样会把所有回调的执行集中在重绘钩子,但不会过滤掉每次重绘的多余调用。我们可以定义一个标志变量,在回调中设置其状态,就能将多余的调用屏蔽:

let enqueued = false;function expensiveOperation() {  console.log("Invoked at", Date.now());  enqueued = false;}window.addEventListener("scroll", () => {  if (!enqueued) {    enqueued = true;    window.requestAnimationFrame(expensiveOperation);  }});

因为重绘是非常频繁的操作,所以这算不上是真正的节流。更好的方法是配合使用一个计时器来限制操作执行的频率。这样,计时器可以限制实际的操作执行间隔,而 requestAnimationFrame() 控制在浏览器的哪个渲染周期中执行:

let enabled = true;function expensiveOperation() {  console.log("Invoked at", Date.now());}window.addEventListener("scroll", () => {  if (enabled) {    enqueued = false;    window.requestAnimationFrame(expensiveOperation);    window.setTimeout(() => (enabled = true), 50);  }});

上面的例子将回调限制为大约 50ms 执行一次。

到此,关于“requestAnimationFrame定时动画屏幕刷新率节流的方法”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

requestAnimationFrame定时动画屏幕刷新率节流的方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

requestAnimationFrame定时动画屏幕刷新率节流的方法

这篇文章主要介绍“requestAnimationFrame定时动画屏幕刷新率节流的方法”,在日常操作中,相信很多人在requestAnimationFrame定时动画屏幕刷新率节流的方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的
2023-07-05

requestAnimationFrame定时动画屏幕刷新率节流示例浅析

这篇文章主要为大家介绍了requestAnimationFrame定时动画屏幕刷新率节流示例浅析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-23

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录