前端开发中requestAnimationFrame和setInterval、setTimeout的介绍和优缺点对比

一、requestAnimationFrame()

requestAnimationFrame是一种在浏览器中实现动画循环的技术,它通过定时器机制来周期性地调用指定的回调函数,以实现网页动画的效果。与传统的setInterval和setTimeout不同,requestAnimationFrame具有更好的浏览器兼容性、更精确的定时控制和更优秀的性能表现。

使用requestAnimationFrame可以将动画的每一帧绘制操作封装为一个回调函数,并将这个回调函数传递给requestAnimationFrame函数。当浏览器准备进行下一帧绘制时,会自动调用这个回调函数,从而实现了动画的循环。

注意:
  • 回调函数的参数是一个时间戳(timestamp),表示当前时间点距离页面加载完成的时间。
  • 回调函数的执行时间间隔是不固定的,它由浏览器根据渲染性能和其他因素进行调度。
  • 如果在一段时间内没有再次调用requestAnimationFrame,则动画会停止。
  • 在浏览器处于非激活状态时,requestAnimationFrame的回调函数不会执行。
  • requestAnimationFrame可以用于实现各种类型的动画效果,包括DOM动画、Canvas动画、SVG动画、WebGL动画等。
语法:
requestAnimationFrame(callback);

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

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

示例

在这个例子中,我们定义了一个名为updateAnimation的函数,用于更新一个元素的动画状态。然后,我们使用requestAnimationFrame函数来启动该动画,它会将updateAnimation函数添加到浏览器下一次重绘之前要执行的队列中。在updateAnimation函数中,我们再次调用requestAnimationFrame函数来请求下一次重绘之前再次执行该函数,从而形成了一个循环,不断更新动画状态。

// 定义一个更新动画的函数  
function updateAnimation() {  // 更新动画状态  const animationElement = document.getElementById('animation');  animationElement.style.left = (animationElement.offsetLeft + 10) + 'px';  // 请求下一次重绘之前再次执行该函数  requestAnimationFrame(updateAnimation);  
}  // 启动动画  
requestAnimationFrame(updateAnimation);
二、setTimeout()

setTimeout()方法用来指定某个函数或字符串在指定的毫秒数之后执行。它返回一个整数,表示定时器的编号,这个值可以传递给clearTimeout()用于取消这个函数的执行

以下代码中,控制台先输出0,大概过1000ms即1s后,输出定时器setTimeout()方法的返回值1

var Timer = setTimeout(function(){console.log(Timer);
},1000);
console.log(0);

如果省略setTimeout的第二个参数,则该参数默认为0

实际上,除了前两个参数,setTimeout()方法还允许添加更多的参数,它们将被传入定时器中的函数中
以下代码中,控制台大概过1000ms即1s后,输出2,而IE9-浏览器只允许setTimeout有两个参数,不支持更多的参数,会在控制台输出NaN

setTimeout(function(a,b){console.log(a+b);
},1000,1,1);
示例

用户自定义的回调函数,通常在浏览器的默认动作之前触发。比如,用户在输入框输入文本,keypress事件会在浏览器接收文本之前触发。因此,下面的回调函数是达不到目的

<input type="text" id="myInput">
<script>
var myInput = document.getElementById('myInput')
myInput.onkeypress = function(event) {this.value = this.value.toUpperCase();
}
</script>

上面代码想在用户输入文本后,立即将字符转为大写。但是实际上,它只能将上一个字符转为大写,因为浏览器此时还没接收到文本,所以this.value取不到最新输入的那个字符

只有用setTimeout改写,上面的代码才能发挥作用

<input type="text" id="myInput">
<script>
var myInput = document.getElementById('myInput')
myInput.onkeypress = function(event) {setTimeout(function(){myInput.value = myInput.value.toUpperCase();});
}
</script>
clearTimeout()

setTimeout函数返回一个表示计数器编号的整数值,将该整数传入clearTimeout函数,取消对应的定时器

一般来说,setTimeout返回的整数值是连续的,也就是说,第二个setTimeout方法返回的整数值比第一个的整数值大1

三、setInterval()

setInterval是一个JavaScript函数,用于按照指定的周期(以毫秒计)来调用函数或计算表达式。它能够以相对准确的时间间隔执行代码,并且可以用于创建定时任务或动画。

setInterval的用法与setTimeout完全一致,区别仅仅在于setInterval指定某个任务每隔一段时间就执行一次,也就是无限次的定时执行

HTML5标准规定,setTimeout的最短时间间隔是4毫秒;setInterval的最短间隔时间是10毫秒,也就是说,小于10毫秒的时间间隔会被调整到10毫秒

大多数电脑显示器的刷新频率是60HZ,大概相当于每秒钟重绘60次。因此,最平滑的动画效的最佳循环间隔是1000ms/60,约等于16.6ms

为了节电,对于那些不处于当前窗口的页面,浏览器会将时间间隔扩大到1000毫秒。另外,如果笔记本电脑处于电池供电状态,Chrome和IE10+浏览器,会将时间间隔切换到系统定时器,大约是16.6毫秒

setInterval方法会返回一个ID值,这个ID值可以用于停止该定时器。可以使用clearInterval(id)函数来停止指定的定时器,其中id是setInterval返回的ID值。

setInterval的工作原理是,当指定的时间间隔过去后,它会自动执行一次指定的代码或函数,然后等待下一个时间间隔。这个过程会一直重复,直到clearInterval被调用或窗口被关闭。

需要注意的是,setInterval并不能保证代码或函数严格按照指定的时间间隔执行。如果代码或函数执行的时间过长,或者处理一些异步操作时,可能会导致实际执行的时间间隔与指定的时间间隔有所偏差。此外,如果浏览器或计算机的性能不足,也可能会导致定时器的执行出现延迟。

示例

在这个例子中,我们首先定义了一个名为intervalId的变量,用于存储setInterval返回的ID值。然后,我们使用setInterval函数执行一个匿名函数,该函数会获取一个元素,并使用当前时间更新该元素的文本内容。setInterval函数会在每次浏览器重绘之前执行该函数,并且每次执行之间会等待1秒钟。最后,我们使用setTimeout函数在10秒钟后停止该定时器。

// 每隔1秒钟更新一次文本内容  
const intervalId = setInterval(function() {  const timeElement = document.getElementById('time');  const currentTime = new Date().toLocaleTimeString();  timeElement.textContent = currentTime;  
}, 1000);  // 在10秒钟后停止定时器  
setTimeout(function() {  clearInterval(intervalId);  
}, 10000);

setInterval可以用于多种场景,比如定时更新数据、定时触发事件、创建动画等。例如,可以使用setInterval来每隔一定时间自动更新UI组件的状态,或者每隔一定时间自动发送HTTP请求获取数据。

四、对比
工作原理:
  • setTimeout:这个函数会将要执行的代码或函数放入事件循环队列中,等待当前代码执行完毕后,再等待指定的时间后执行一次。如果设置了定时器,那么每隔一定时间就会执行一次代码,直到 clearTimeout 被调用或窗口被关闭。

  • setInterval:与 setTimeout 类似,setInterval 也会将要执行的代码或函数放入事件循环队列中,但它在指定的时间间隔后会一直重复执行,直到 clearInterval 被调用或窗口被关闭。也就是说,setInterval 会不断地调用函数,直到被取消。

  • requestAnimationFrame:这个函数的工作原理与 setInterval 和 setTimeout 略有不同。它会将回调函数加入到浏览器下一次重绘之前要执行的队列中。这样做的目的是为了确保动画的流畅度,因为浏览器会自动优化这个API,只在浏览器处于激活状态并且页面处于可见状态时才会执行回调函数。此外,requestAnimationFrame 会根据系统的刷新率来自动匹配时间间隔,从而确保每帧动画的间隔时间尽可能地准确。

区别:
  • 执行时机:requestAnimationFrame是由浏览器提供的API,它会在浏览器下一次重绘之前执行回调函数。这意味着它能够确保动画的流畅度,并且能够自动匹配系统的刷新率。相比之下,setInterval和setTimeout会在指定的时间间隔后执行回调函数,无论浏览器是否处于激活状态或正在进行其他操作。

  • 性能优化:requestAnimationFrame由浏览器自动优化,只在浏览器处于激活状态并且页面处于可见状态时才会执行回调函数。这可以节省CPU、GPU和内存的使用,特别是在移动设备上。相比之下,setInterval和setTimeout不会自动优化,如果页面处于隐藏或不可见状态,它们会继续执行回调函数,这可能会导致资源的浪费。

  • 回调函数执行时间:requestAnimationFrame的回调函数会在浏览器下一次重绘之前执行,因此它能够确保回调函数的执行时间相对准确。相比之下,setInterval和setTimeout的回调函数执行时间取决于浏览器事件循环中的队列和执行时间,因此可能会有一定的延迟。

  • 停止操作:requestAnimationFrame的回调函数只会在浏览器下一次重绘之前执行一次,因此可以通过清除队列中的回调函数来停止操作。相比之下,setInterval和setTimeout会不断地执行回调函数,直到clearInterval或clearTimeout被调用或关闭页面为止。

  • 函数节流:在高频率事件(resize,scroll等)中,为了防止在一个刷新间隔内发生多次函数执行,使用requestAnimationFrame可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。

应用场景
  • setTimeout:可用于在网页加载后延迟执行某些操作,例如加载页面内容、初始化组件等。也可用于定时触发某些操作,例如定时发送数据、定时检查任务等。

  • setInterval:常用于需要周期性执行的操作,例如定时更新数据、定时触发事件等。在web端,如果列表需要定时更新,可以使用setInterval来定时获取列表的请求。另外,如果需要在某一特定情况下清除定时任务,可以使用clearInterval来停止定时器。

  • requestAnimationFrame:主要用于实现流畅的动画效果。它会在浏览器下一次重绘之前执行指定的函数,避免了频繁的重绘导致的性能问题。requestAnimationFrame会自动匹配系统的刷新率,从而确保每帧动画的间隔时间尽可能地准确。在需要反复触发的情况下,使用requestAnimationFrame可以避免连续调用导致的相互干扰。

五、示例

现在分别使用 setInterval、setTimeout 和 requestAnimationFrame 这三个方法制作一个简单的进制度效果

<div style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;" id="div">0%</div><button id="btn">run</button><script>var timer;var btn = document.getElementById('btn')var myDiv = document.getElementById('div')// 1.requestAnimationFramebtn.onclick = function () {myDiv.style.width = '0';cancelAnimationFrame(timer);timer = requestAnimationFrame(function fn() {if (parseInt(myDiv.style.width) < 500) {myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';myDiv.innerHTML = parseInt(myDiv.style.width) / 5 + '%';timer = requestAnimationFrame(fn);} else {cancelAnimationFrame(timer);}});}// 2.setIntervalbtn.onclick = function () {clearInterval(timer);myDiv.style.width = '0';timer = setInterval(function () {if (parseInt(myDiv.style.width) < 500) {myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';myDiv.innerHTML = parseInt(myDiv.style.width) / 5 + '%';} else {clearInterval(timer);}}, 16);}// 3.setTimeoutbtn.onclick = function () {clearTimeout(timer);myDiv.style.width = '0';timer = setTimeout(function fn() {if (parseInt(myDiv.style.width) < 500) {myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';myDiv.innerHTML = parseInt(myDiv.style.width) / 5 + '%';timer = setTimeout(fn, 16);} else {clearTimeout(timer);}}, 16);}
</script>

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

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

相关文章

Redis队列原理解析:让你的应用程序运行更加稳定!

一、消息队列简介 消息队列&#xff08;Message Queue&#xff09;&#xff0c;字面意思就是存放消息的队列。最简单的消息队列模型包括 3 个角色&#xff1a; 消息队列&#xff1a;存储和管理消息&#xff0c;也被称为消息代理&#xff08;Message Broker&#xff09;生产者…

Json格式化

Json格式化 大家好&#xff0c;我是微赚淘客机器人的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; Json格式化&#xff1a;让数据更亮眼&#xff0c;解密Json的奇妙世界 在现代Web开发中&#xff0c;Json&#xff08;JavaScript Object N…

Turtle绘制菱形-第11届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第16讲。 Turtle绘制菱形&a…

六.聚合函数

聚合函数 1.什么是聚合函数1.1AVG和SUM函数1.2MIN和MAX函数1.3COUNT函数 2.GROUP BY2.1基本使用2.2使用多个列分组2.3GROUP BY中使用WITH ROLLUP 3.HAVING3.1基本使用3.2WHERE和HAVING的区别 4.SELECT的执行过程4.1查询的结构4.2SELECT执行顺序4.3SQL执行原理 1.什么是聚合函数…

pip的常见60条基本命令和使用详解

pip是Python的包管理工具&#xff0c;用于安装、升级和卸载Python包。以下是pip的常见基本命令和使用详解&#xff1a; 1. 安装包&#xff1a;pip install package_name 该命令用于安装指定的Python包。例如&#xff0c;要安装名为xlwt的包&#xff0c;可以运行命令"pip i…

用友 U8总账凭证打印设置

总账--凭证打印——设置 是设置凭证打印显示的格子框&#xff0c;勾上就有框&#xff0c;去掉就没有框。

多家安全设备存在远程命令执行漏洞复现 [附POC]

文章目录 多家安全设备(防火墙产品)存在远程命令执行漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响产品0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现多家安全设备(防火墙产品)存在远程命令执行漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相…

xcode-文件

IOSDeviceSupoprt 共享缓存库 当你使用新的 iOS 设备连接到 Xcode 时&#xff0c;Xcode 会自动下载并存储相应版本的设备支持文件。 每个 iOS 版本都有一个对应的设备支持文件集&#xff0c;这些文件包含有关设备架构和操作系统的信息&#xff0c;以便 Xcode 能够正确地调试和…

判断css文字发生了截断,增加悬浮提示

示例&#xff1a; 固定显示宽度&#xff0c;溢出显示...&#xff0c;利用了css的属性&#xff0c;想要实现成下面这样&#xff1a; 针对溢出的文字&#xff0c;hover显示全部。 提示很好加&#xff0c;使用tooltip组件就行了&#xff0c;难点是如何判断是否发生了文字溢出。…

JS数组与它的42个方法

前言 数组在js中作为一个非常重要的类型之一&#xff0c;在我们对数据处理&#xff0c;存储数据&#xff0c;条件渲染的时候经常会用到&#xff0c;所以随着ES的不断更新&#xff0c;数组的方法也是越来越多&#xff0c;也让我们使用数组对数据操作的时候&#xff0c;越来越简…

【Python百宝箱】数据巨轮启航:Python大数据处理库全攻略,引领数据科学新浪潮

前言 在当今数据爆炸的时代&#xff0c;处理大规模数据集已经成为数据科学和工程领域的关键挑战。Python作为一种强大而灵活的编程语言&#xff0c;吸引着越来越多的数据专业人士。本文旨在为读者提供一份全面的指南&#xff0c;介绍了Python中几个重要的大数据处理库&#xf…

竞赛保研 python 爬虫与协同过滤的新闻推荐系统

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; python 爬虫与协同过滤的新闻推荐系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&…

天线的分类

1.按工作性质可分为发射天线和接收天线。 2、按用途可分为通信天线、广播天线、电视天线、雷达天线等。 3、按方向性可分为全向天线和定向天线等。 4、按工作波长可分为超长波天线、长波天线、中波天线、短波天线、超短波天线、微波天线等。 5、按结构形式和工作原理可分为…

Python求小于m的最大10个素数

为了找到小于m的最大10个素数&#xff0c;我们首先需要确定m的值。然后&#xff0c;我们可以使用一个简单的算法来检查每一个小于m的数字是否是素数。 下面是一个Python代码示例&#xff0c;可以找到小于m的最大10个素数&#xff1a; def is_prime(n): if n < 1: …

Conda 使用教程大全来啦

什么是 Conda&#xff1f; Conda 是一款功能强大的软件包管理器和环境管理器&#xff0c;您可以在 Windows 的 Anaconda 提示符或 macOS 或 Linux 的终端窗口中使用命令行命令 Conda 可以快速安装、运行和更新软件包及相关依赖项。Conda 可以在本地计算机上创建、保存、加载和…

swing快速入门(八)

注释很详细&#xff0c;直接上代码 上一篇 新增内容 cardLayout布局管理器 事件监听器的创建与绑定 多种布局与容器的结合使用 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;public class swing_test_6 {public static v…

佛山数字孪生赋能工业智能制造,助力制造业企业数字化转型

佛山数字孪生赋能工业智能制造&#xff0c;助力制造业企业数字化转型。数字孪生驱动的仿真服务可以模拟产品的各种真实功能&#xff0c;为不同的用户切换不同的应用场景。产品介绍、咨询和体验服务都可以通过产品数字孪生来完成。产品数字孪生在交易时可以交付给客户。产品销售…

【ARM Trace32(劳特巴赫) 使用介绍 14 -- Go.direct 介绍】

请阅读【Trace32 ARM 专栏导读】 文章目录 Trace32 Go.directGo配合程序断点使用Go 配合读写断点使用Go 快速回到上一层函数 System.Mode Go Trace32 Go.direct TRACE32调试过程中&#xff0c;会经常对芯片/内核进行控制&#xff0c;比如全速运行、暂停、单步等等。这篇文章先…

Android Binder 调用栈

Java Binder 调用栈 发起 binder 请求 native: #00 pc 000000000006e1c4 /system/lib64/libc.so (__ioctl4)native: #01 pc 00000000000290d0 /system/lib64/libc.so (ioctl136)native: #02 pc 000000000005a5e4 /system/lib64/libbinder.so (android::IPCThreadState::tal…

Go——协程

协程 协程是Go语言最大的特色之一。 1、协程的概念 协程并不是Go发明的概念&#xff0c;支持协程的变成语言有很多。Go在语言层面直接提供对协程的支持称为goroutine。 1.1 基本概念 进程 进程是应用程序启动的实例&#xff0c;每个进程都有独立的内存空间&#xff0c;不同…