requestAnimationFrame 解析

news2024/12/1 0:39:07

文章目录

    • 什么是 requestAnimationFrame
    • 为什么 setInterval 实现动画会有一些抖动感
    • 使用 requestAnimationFrame
    • requestAnimationFrame 对比 setInterval

本文将给大家介绍一个使用 js 实现动画的利器,requestAnimationFrame,我们一般情况下,在 js 实现一个动画,一般是使用 setInterval 实现,不过通常使用这个方法实现动画的时候,细看能够看见一些抖动感

什么是 requestAnimationFrame

  1. requestAnimationFrame 是浏览器提供的一个方法,我们可以通过 requestAnimationFrame 来告诉浏览器我们需要执行一个动画,并且这个动画触发的时机是浏览器在下次重绘之前调用指定的回调函数更新动画
  2. 该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行
  3. 当然也有一些需要注意的地方:若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用 requestAnimationFrame()。因为 requestAnimationFrame() 是一次性的
  4. 在大多数遵循 W3C 建议的浏览器中,回调函数执行次数通常与浏览器屏幕刷新次数相匹配
  5. 而如果想要取消 requestAnimationFrame 执行,可以通过 cancelAnimationFrame 方法

为什么 setInterval 实现动画会有一些抖动感

  1. 这个原因可能有不少,但是主要的就是 浏览器渲染帧的不同步

  2. 为什么会不同步呢?主要原因是浏览器无法确定定时器的回调函数的执行时机

  3. 我们知道 setInterval 是一个异步的任务,只有当同步任务执行完成之后才会执行异步任务,假设我们设置的 setInterval 是 20ms 执行一次,那么如果同步代码执行的时间是 10ms,也就表示实际上 setInterval 执行的时候已经隔了 30ms 的时间了

  4. 这是一点,那我们在猜想一下,按照 60 帧率来计算的话,应该是 16.7ms 执行一次,就可以达到一个比较细腻的动画,那么如果我们将 setInterval 的时间设置为 16.7ms 可以解决这个问题吗,也是不行的,还是这个异步的问题,加上等待同步代码执行时间,这个时间一定是不精确的,何况本身浏览器的计时存在细小的误差

  5. 为了方便理解,我们还是回到这个开始设置 20ms 的时间,按照预期 60 帧渲染的话,那么不算其他干扰的情况,那么执行的时间线如下:

    在这里插入图片描述

  6. 可以看到,第一帧没有渲染,20ms的时候执行了 setInterval 代码了,但是就需要等待下一次的执行时机,也就第二帧,而如果假设是 10ms 的话,那么第一帧可以找到,但是在执行第二帧的时候,其实 setInterval 执行了三次,也就是说在第二帧本该执行第二次 setInterval 所设置的动画数值,变了第三次 setInterval 设置的动画数值,出现了一次跳跃,那自然看起来也会存在抖动感

  7. 正是因为由于这种不同步,就导致了一次执行渲染一针或者多帧,或者当前帧没有渲染,下一次执行的时候数值跳跃等等,从而导致动画存在抖动感

  8. 这个更加具体一点大家可以参考手绘动画翻页这种效果,如果翻到某一页突然停一下,或者某两页或者几页黏在一起,被当做一页翻过去的时候,就可以名显的感觉到这个不连贯的感觉

  9. 或者有人说,我可以强制触发reflow来触发啊,那还是这个问题,屏幕的刷新率是固定的,你重绘时机过早也不会被展示出来,也不会被用户感知到,等于无效的操作,那么还是无法解决这个问题

使用 requestAnimationFrame

  1. 相信在经过上面 setInterval 实现动画为什么存在抖动感的解析,就知道应该要怎么解决,解决方案就是在每一帧渲染之前,就处理好每一帧需要表现的动画样式和一些数据,然后就可以在每一帧时机渲染的时候处理正确的动画效果,这样就可以保证我们的动画拥有相对细腻的效果了

  2. 而 requestAnimationFrame 就可以帮助我们完成这个效果

  3. requestAnimationFrame 是只会执行一次的,所以我们如果需要利用 requestAnimationFrame 实现动画效果的话,往往需要递归,也就是如下的形式,如下:

    function run(){
        requestAnimationFrame(run)
    }
    requestAnimationFrame(run)
    

requestAnimationFrame 对比 setInterval

  1. 实现代码:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>requestAnimationFrame</title>
      <style>
        * {
          margin: 0;
          padding: 0;
          box-sizing: border-box;
        }
    
        .sign {
          width: 500px;
          height: 220px;
          border-right: 2px solid #000;
          position: relative;
          margin-left: 20px;
        }
    
        .box {
          width: 100px;
          height: 100px;
          background-color: salmon;
          position: absolute;
          left: 0;
          top: 0;
        }
    
        .box1 {
          top: 120px;
          background-color: skyblue;
          word-wrap: break-word;
        }
    
        .btns {
          margin-left: 20px;
          margin-top: 30px;
        }
      </style>
    </head>
    
    <body>
      <div class="sign">
        <div class="box">setInterval</div>
        <div class="box box1">requestAnimationFrame</div>
      </div>
      <div class="btns">
        <button class="s-btn">setInterval</button>
        <button class="r-btn">requestAnimationFrame</button>
        <button class="btn">一起执行</button>
      </div>
    
      <script>
        const box = document.querySelector('.box');
        const box1 = document.querySelector('.box.box1');
        const sBtn = document.querySelector('.s-btn')
        const rBtn = document.querySelector('.r-btn')
        const btn = document.querySelector('.btn')
    
        let boxLeft = 0
        let boxId = null
    
        let box1Left = 0
        let box1Id = null
    
    
        sBtn.addEventListener('click', () => {
          boxId = setInterval(() => {
            boxLeft++
            box.style.left = boxLeft + 'px'
            if (boxLeft >= 400) {
              clearInterval(boxId)
              boxId = null
            }
          }, 1000 / 60)
        })
    
        function run() {
          box1Left++
          box1.style.left = box1Left + 'px'
          if (box1Left >= 400) {
            cancelAnimationFrame(box1Id)
            box1Id = null
            return
          }
          requestAnimationFrame(run)
        }
    
        rBtn.addEventListener('click', () => {
          box1Id = requestAnimationFrame(run)
        })
    
        btn.addEventListener('click', () => {
          sBtn.click()
          rBtn.click()
        })
    
      </script>
    
    </body>
    
    </html>
    
  2. 屏幕刷新率为 60hz 时效果

    在这里插入图片描述

  3. 屏幕刷新率为 165hz 时

    在这里插入图片描述

  4. 由于这种 gif 的原因,可能实际感受不如在屏幕上看的明显,但是可以大致感知出来 setInterval 的那种抖动感,而且 setInterval 只能设置固定的时间,是无法契合当前的屏幕的刷新率的

  5. 这里在补充一点性能上的区别,这个就先了解一下他们在后台的运行机制:

    1. requestAnimationFrame() 运行在后台标签页或者隐藏的 <iframe> 里时,requestAnimationFrame()` 会被暂停调用以提升性能和电池寿命

    2. 而 setInterval 在后台也是不会停止调用的会继续在浏览器的内存中调用,消耗性能,比如最开始编写轮播图的时候,如果页面隔一段时间切换回来之后,会导致轮播图切换的非常快,就是因为没有停止执行,而切换回来之后,把失去的值都补上,这个也是可以验证的,比如我们把 setInterval 执行改为 2000ms,每次增加 50px,来看一下效果,如图

      在这里插入图片描述

    3. 通过这个是可以看到切换回来的时候,一下子就跳跃了一大段距离,就表示实际是没有停止执行的,一直改变着移动的数值,切换胡来的时候才会进行了跳跃式的移动

  6. 当然动画最优选还是 css3,不过有些动画总会需要 js 的介入嘛

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1348077.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java零拷贝zero copy MappedByteBuffer

目录 调用操作系统的 mmap 未使用 mmap 的文件通过网络传输的过程 使用 mmap 的文件通过网络传输的过程 使用例子 调用操作系统的 sendfile() 在 java 中的具体实现 mmap的优劣 mmap 的不足 mmap 的优点 mmap 的使用场景 对于零拷贝&#xff08;zero copy&#xff09…

数据资产入表之——数据确权

关注WX公众号&#xff1a; commindtech77&#xff0c; 获得数据资产相关白皮书下载地址 1. 回复关键字&#xff1a;数据资源入表白皮书 下载 《2023数据资源入表白皮书》 2. 回复关键字&#xff1a;光大银行 下载 光大银行-《商业银行数据资产会计核算研究报告》 3. 回复关键字…

计算机网络 (期末救命版)

文章目录 Ⅰ 网络概述1. 互联网概述与组成2. 计算机网络的类别3. 计算机网络的性能指标4. 计算机网络体系结构 Ⅱ 物理层1. 物理层的任务2. 信道复用技术 Ⅲ 数据链路层1. 点对点信道2. 基本问题3. 点对点协议 PPP4. 使用广播信道的数据链路层 Ⅳ 网络层1. 网络层的服务2. 网际…

怎么挑选猫粮?挑选主食冻干猫粮的步骤

各位铲屎官都知道猫天性是食肉动物&#xff0c;无肉不欢的。而冻干猫粮对于猫咪来说是最好还原猫咪食肉天性的食物&#xff0c;不仅可以当成猫咪的主食&#xff0c;也可以用来给猫咪当成零食&#xff0c;帮助猫咪补充营养。冻干猫粮是经过真空冷冻干燥处理的鲜肉&#xff0c;能…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存&#xff08;CustomData&#xff09;功能&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机的数据保存&#xff08;CustomData&#xff09;功能的技术背景CameraExplorer如何使用图像剪切&#xff…

移动端开发框架mui代码在安卓模拟器上运行2(HbuilderX连接到模拟器)模拟器窗口及多开设置

开发工具 HBuilder X 3.8.12.20230817 注意&#xff1a;开发工具尽量用最新的或较新的。太旧的版本在开发调试过程中可能会出现莫名其妙的问题。 接上篇&#xff0c;移动端开发框架mui代码在安卓模拟器上运行&#xff08;HbuilderX连接到模拟器&#xff09;&#xff0c;这篇主要…

Python开发环境[PycharmEclipseAnaconda]

Pycharm配置Python开发环境 每种语言的开发工具都有很多&#xff0c;如果写一些小的脚本或者小的工具&#xff0c;建议直接使用命令行或者Python自带的IDLE&#xff0c;如果进行大型的开发工作建议使用Pycharm&#xff0c;当然这属于个人喜好。 虽然Pycharm给了我们一个美观的…

【Python特征工程系列】教你利用AdaBoost模型分析特征重要性(源码)

这是Python特征工程系列原创文章&#xff0c;我的第187篇原创文章。 一、问题 应用背景介绍&#xff1a; 如果有一个包含数十个甚至数百个特征的数据集&#xff0c;每个特征都可能对你的机器学习模型的性能有所贡献。但是并不是所有的特征都是一样的。有些可能是冗余的…

树与图的搜索

目录 树与图的深度优先遍历 树与图的宽度优先遍历 树与图的深度优先遍历 题目如下&#xff1a; 树是一种特殊的图&#xff0c;是一种无环连通图&#xff0c;图分两种&#xff0c;无向图&#xff08;边无方向&#xff09;和有向图&#xff08;边有方向&#xff09;&#xff0…

蓝牙物联网健康管理系统设计方案

随着我国医疗体制改革的快速发展&#xff0c;以及信息科技的更新换代&#xff0c;远程健康管理逐步成为医疗卫生健康服务的发展趋势。物联网技术推动着医疗健康服务体系发生重大改变&#xff0c;传统的定期至社区医院问诊的保健模式&#xff0c;被远程健康服务模式所取代。开发…

数据转换的三剑客:Pandas 中 apply、map 和 applymap 方法的应用指南

数据转换的三剑客&#xff1a;Pandas 中 apply、map 和 applymap 方法的应用指南 ​ 在 Pandas 中&#xff0c;apply、map 和 applymap 是常用的数据转换和处理方法&#xff0c;它们为数据分析和数据处理提供了灵活的功能。这些方法可以根据具体的需求选择合适的方法进行操作。…

扩散模型基础

扩散模型发展至今日&#xff0c;早已成为各大机器学习顶会的香饽饽。本文简记扩散模型入门相关代码&#xff0c;主要参阅李忻玮、苏步升等人所编著的《扩散模型从原理到实战》 文章目录 1. 简单去噪模型1.1 简单噪声可视化1.2 去噪模型1.3 小结 2 扩散模型2.1 采样过程2.2 上科…

线性代数基础知识

计算机视觉一些算法中常会用到线性代数的一些知识&#xff0c;为了便于理解和快速回忆&#xff0c;博主这边对常用的一些知识点做下整理&#xff0c;主要来源于如下这本书籍。 1. 矩阵不仅仅是数字排列而已&#xff0c;不然也不会有那么大精力研究它。其可以表示一种映射 关于…

《PCI Express体系结构导读》随记 —— 第I篇 第2章 PCI总线的桥与配置(1)

前言中曾提到&#xff1a;本章重点介绍PCI桥。 在PCI体系结构中含有两类桥&#xff1a;一类是HOST主桥&#xff1b;另一类是PCI桥。在每一个PCI设备中&#xff08;包括PCI桥&#xff09;&#xff0c;都含有一个配置空间。这个配置空间由HOST主桥管理&#xff0c;而PCI桥可以转…

CycleGAN 是如何工作的?

一、说明 CycleGAN即循环对抗网络&#xff0c;是图像翻译成图像的模型&#xff1b;是Pix2Pix模型的扩展&#xff0c;区别在于&#xff0c;Pix2Pix模型需要输入图像和目标图像成对给出训练&#xff0c;CycleGAN则不需要&#xff0c;例如&#xff1a;从 SAR 生成 RGB 图像、从 RG…

使用ASP.NET MiniAPI 调试未匹配请求路径

本文将介绍如何在使用ASP.NET MiniAPI时调试未匹配到的请求路径。我们将详细讨论使用MapFallback方法、中间件等工具来解决此类问题。 1. 引言 ASP.NET MiniAPI是一个轻量级的Web API框架&#xff0c;它可以让我们快速地构建和部署RESTful服务。然而&#xff0c;在开发过程中如…

S7-1200 PLC回原方式详细解读(SCL代码)

S7-1200PLC脉冲轴位置控制功能块的介绍,可以查看下面链接文章: https://rxxw-control.blog.csdn.net/article/details/135299302https://rxxw-control.blog.csdn.net/article/details/135299302脉冲轴工艺对象组态设置介绍 https://rxxw-control.blog.csdn.net/article/det…

算法(3)——二分查找

一、什么是二分查找 二分查找也称折半查找&#xff0c;是在一组有序(升序/降序)的数据中查找一个元素&#xff0c;它是一种效率较高的查找方法。 二、二分查找的原理 1、查找的目标数据元素必须是有序的。没有顺序的数据&#xff0c;二分法就失去意义。 2、数据元素通常是数值…

推荐系统中 排序策略 CTR 动态加权平均法

CTR&#xff08;Click-Through Rate&#xff09;动态加权平均法是一种用于计算广告点击率的方法&#xff0c;其中每个点击率被赋予一个权重&#xff0c;这个权重可以随着时间、事件或其他因素而动态调整。这种方法旨在更灵活地反映广告点击率的变化&#xff0c;使得最近的数据更…

HTML与CSS

目录 1、HTML简介 2、CSS简介 2.1选择器 2.1.1标签选择器 2.1.2类选择器 2.1.3层级选择器(后代选择器) 2.1.4id选择器 2.1.5组选择器 2.1.6伪类选择器 2.2样式属性 2.2.1布局常用样式属性 2.2.2文本常用样式属性 1、HTML简介 超文本标记语言HTML是一种标记语言&…