百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

你确定还不来了解一下JS的rAF(js中ref)

toyiye 2024-04-04 11:27 31 浏览 0 评论

不会吧,不会吧,现在都2020年了不会还真人有人不知道JS的rAF吧???

rAF

简介

rAF是requestAnimationFrame的简称;

我们先从字面意思上理解requestAnimationFrame「request - 请求」「Animation - 动画」「Frame - 帧率;框架」rAF难道是JS的动画框架???,结果显而易见并不是。但确实rAF和动画有关系

我们先来看一下MDN官网对的requestAnimationFrame解释:

window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行

浏览器兼容性


requestAnimationFrame兼容IE10及以上,这时候有人会有疑问,怎么才到IE10啊,但其实我们最常使用的CSS3 animation属性也是IE10之后才有的,在IE9之前想要实现动画基本使用的是setTimeout/setInterval实现

作用及用法

requestAnimationFrame简称rAF,它是浏览器全局对象window的一个方法。

相比于setTimeout的在固定时间后执行对应的动画函数,rAF用于指示浏览器在下一次重新绘制屏幕图像时, 执行其提供的回调函数。

这也是rAF的最大优势–它能够保证我们的动画函数的每一次调用都对应着一次屏幕重绘,从而避免setTimeout通过时间定义动画频率,与屏幕刷新频率不一致导致的丢帧。

详细用法

requestAnimationFrame语法如下:


window.requestAnimationFrame(callback)

「参数;callback」 下一次重绘之前更新动画帧所调用的函数(即上面所说的回调函数)。该回调函数会被传入DOMHighResTimeStamp参数,该参数与performance.now()的返回值相同,它表示requestAnimationFrame()开始去执行回调函数的时刻。

「返回值」一个 long 整数,请求 ID ,是回调列表中唯一的标识。是个非零值,没别的意义。你可以传这个值给 window.cancelAnimationFrame() 已取消回调函数。

DOMHighResTimeStamp 指的是一个double类型,用于存储毫秒级的时间值。这种类型可以用来描述离散的时间点或者一段时间(两个离散时间点之间的时间差)。

performance.now()方法返回一个精确到毫秒的DOMHighResTimeStamp 。


它的实际常见用法类似于setTimeout,只是不需要设置时间间隔而已。如下:


const element = document.getElementById('some-element-you-want-to-animate'); 
let start;

function step(timestamp) {
  // timestamp回调函数传入的`DOMHighResTimeStamp`参数,也就是存储毫秒级的时间值
  if (start === undefined)
    start = timestamp;
  const elapsed = timestamp - start;

  //这里使用`Math.min()`确保元素刚好停在200px的位置。
  element.style.transform = 'translateX(' + Math.min(0.1 * elapsed, 200) + 'px)';

  if (elapsed < 2000) { // 在两秒后停止动画
    window.requestAnimationFrame(step);
  }
}

window.requestAnimationFrame(step);

上述代码的作用在每一次屏幕显示图像的更新中,都将元素向左移动1px,停在200px位置上。

实际使用示例

「上才艺,E G M,E G M E G M E G M」

我们以在3000毫秒内移动1500px距离的动画为例

setTimeout的实现方式

以下代码通过setTimeout每10毫秒为间隔时间改变一次元素的位置以实现元素的动画效果, 当然,可以通过改变这个间隔时间来微调动画效果,可是你永远没有办法确定最优方案,因为它总会和刷新频率存在交叉。


<div id="div" style="width:100px; height:100px; background-color:#000; position: absolute;left:0; top:0;">
    
</div>

<script type="text/javascript">
let divEle = document.getElementById("div");

const distance = 1500; // 需要移动的距离
const timeCount = 3000; // 需要使用的时间

const intervalTime = 10; // 设置间隔时间为10ms
let runCount = timeCount / intervalTime; // 相除得到运行次数
let moveValue = distance / runCount; // 每次运行移动的距离

function handler() {
    let left = parseInt(divEle.style.left);
    if(left >= distance) {
      // 当距离左侧的距离超出需要移动的距离停止
        return;
    }
    divEle.style.left = left + moveValue;
    window.setTimeout(handler, intervalTime);
}

window.setTimeout(handler, intervalTime);
</script>

requestAnimationFrame的实现方式

「从setTimeout切换到 requestAnimationFrame很容易,因为它们都安排了一个回调。对于连续动画,在调用动画函数之后再次调用requestAnimationFrame。」

request 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成(这点很像虚拟DOM不是~),并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,这样就不会出现过度渲染的问题,保证了流畅的需求以及浏览器的完美渲染。


<div id="div" style="width:100px; height:100px; background-color:#000; position: absolute;left:0; top:0;">
    
</div>

<script type="text/javascript">

let divEle = document.getElementById("div");

const distance = 1500; // 需要移动的距离
const timeCount = 3000; // 需要使用的时间

function handler( time ) {
    // time为rAF返回的毫秒级时间单位,当time的大于timeCount的值则停止
    // time理论上是从 1 开始到timeCount定义的3000,
    if(time > timeCount) {
        time = timeCount;
    }
    // 这句代码的作用是 time理论上是从 1 至 3000
    // 当到达3000的时候,time * distance / timeCount得到的一定是distance的值1500
    divEle.style.left = time * distance / timeCount;
    window.requestAnimationFrame( handler ); // 循环调用,渲染完成会停止
}

 window.requestAnimationFrame( handler );
</script>
    

requestAnimationFrame的优点

为什么不使用settimeout?

setTimeout通过设定一个时间间隔来不断的更新屏幕图像,从而完成动图。 它的优点是可控性高,可以进行编码式的动画效果实现。

setTimeout缺点:

  1. 「造成无用的函数运行开销:」

也就是过度绘制,同时因为更新图像的频率和屏幕的刷新重绘制步调不一致,会产生丢帧,在低性能的显示器动画看起来就会卡顿。

  1. 「当网页标签或浏览器置于后台不可见时,仍然会执行,造成资源浪费」
  2. 「API本身达不到毫秒级的精确:」

如果使用 setTimeout或者setInterval 那么需要我们制定时间 假设给予 (1000/60)理论上就可以完成60帧速率的动画。所以事实是浏览器可以“强制规定时间间隔的下限(clamping th timeout interval)”,一般浏览器所允许的时间在5-10毫秒,也就是说即使你给了某个小于10的数,可能也要等待10毫秒。

  1. 「浏览器不能完美执行:」

当动画使用10ms的settimeout绘制动画时,您将看到一个时序不匹配,如下所示。


我们的显示屏一般是「16.7ms(即60FPS)的显示频率」,上图的第一行代表大多数监视器上显示的「16.7ms显示频率」,上图的第二行代表「10ms的典型setTimeout」。由于在显示刷新间隔之前发生了另一个绘制请求,因此无法绘制每次的第三个绘制(红色箭头指示)。这种透支会导致动画断断续续,「因为每三帧都会丢失」。计时器分辨率的降低也会对电池寿命产生负面影响,并降低其他应用程序的性能。

如果使用requestAnimationFrame可以解决setTimeout的丢帧问题,因为它使应用程序时通知(且仅当)的浏览器需要更新页面显示,渲染时间由系统处理。因此,应用程序与浏览器绘画间隔完全一致,并且仅使用适当数量的资源。

requestAnimationFrame的好处

相比于setTimeout的在固定时间后执行对应的动画函数,requestAnimationFrame用于指示浏览器在下一次重新绘制屏幕图像时, 执行其提供的回调函数。

  • 「使浏览器画面的重绘和回流与显示器的刷新频率同步」它能够保证我们的动画函数的每一次调用都对应着一次屏幕重绘,从而避免setTimeout通过时间定义动画频率,与屏幕刷新频率不一致导致的丢帧。
  • 「节省系统资源,提高性能和视觉效果」在页面被置于后台或隐藏时,会自动的停止,不进行函数的执行,当页面激活时,会重新从上次停止的状态开始执行,因此在性能开销上也会相比setTimeout小很多。

兼容问题

目前的时间点上,几乎所有的浏览器现行版本都支持了requestAnimationFrame函数。但在一部分浏览器上还需要加上兼容性前缀。 下面这是比较全面的方法用来使requestAnimation兼容各浏览器:


(function() {
    var lastTime = 0;
    var vendors = ['webkit', 'moz']; // 浏览器前缀
    // 当window.requestAnimationFrame不存在时执行for循环,添加前缀
    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'];
    }

    //当添加前缀后依旧不存在,则使用setTimeout替代
    if (!window.requestAnimationFrame) {
        window.requestAnimationFrame = function(callback, element) {
            var currTime = new Date().getTime();
            var timeToCall = Math.max(0, 16.7 - (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);
        };
    }
}());

然后,我们就可以以使用setTimeout的感觉使用requestAnimationFrame方法制作动画啦!

结尾

如有疑问,可在下方留言,会第一时间进行回复

谢谢你愿意花时间阅读这篇文章,希望可以对你有所帮助!

最后,小编想说:我是一名python开发工程师,

整理了一套最新的python系统学习教程,

想要这些资料的可以关注私信小编“01”即可,希望能对你有所帮助。

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码