前端开发必备:requestAnimationFrame、setInterval、setTimeout——功能解析与优劣对比

简介: 前端开发必备: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.requestAnimationFrame
    btn.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.setInterval
    btn.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.setTimeout
    btn.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>
目录
相关文章
|
4月前
|
人工智能 监控 算法
销售易CRM:功能与优势全解析
销售易CRM是国内领先的客户关系管理(CRM)系统,提供强大的销售管理、全方位客户管理、丰富的营销自动化工具、智能AI赋能及灵活的开放性平台。其功能涵盖线索获取、商机管理、客户画像、营销活动策划、智能预测等,支持企业高效管理客户、优化业务流程、提升销售效率和客户满意度。通过灵活的二次开发和API接口,销售易CRM可无缝集成企业现有系统,助力企业在数字化转型中实现业绩高质量增长。
|
4月前
|
弹性计算 运维 安全
优化管理与服务:操作系统控制平台的订阅功能解析
本文介绍了如何通过操作系统控制平台提升系统效率,优化资源利用。首先,通过阿里云官方平台开通服务并安装SysOM组件,体验操作系统控制平台的功能。接着,详细讲解了订阅管理功能,包括创建订阅、查看和管理ECS实例的私有YUM仓库权限。订阅私有YUM仓库能够集中管理软件包版本、提升安全性,并提供灵活的配置选项。最后总结指出,使用阿里云的订阅和私有YUM仓库功能,可以提高系统可靠性和运维效率,确保业务顺畅运行。
|
4月前
|
JSON 自然语言处理 前端开发
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
200 72
【01】对APP进行语言包功能开发-APP自动识别地区ip后分配对应的语言功能复杂吗?-成熟app项目语言包功能定制开发-前端以uniapp-基于vue.js后端以laravel基于php为例项目实战-优雅草卓伊凡
|
3月前
|
存储 前端开发 JavaScript
调用DeepSeek API增强版纯前端实现方案,支持文件上传和内容解析功能
本方案基于DeepSeek API增强版,提供纯前端实现的文件上传与内容解析功能。通过HTML和JavaScript,用户可选择文件并调用API完成上传及解析操作。方案支持多种文件格式(如PDF、TXT、DOCX),具备简化架构、提高响应速度和增强安全性等优势。示例代码展示了文件上传、内容解析及结果展示的完整流程,适合快速构建高效Web应用。开发者可根据需求扩展功能,满足多样化场景要求。
1108 64
|
4月前
|
人工智能 API 语音技术
HarmonyOS Next~鸿蒙AI功能开发:Core Speech Kit与Core Vision Kit的技术解析与实践
本文深入解析鸿蒙操作系统(HarmonyOS)中的Core Speech Kit与Core Vision Kit,探讨其在AI功能开发中的核心能力与实践方法。Core Speech Kit聚焦语音交互,提供语音识别、合成等功能,支持多场景应用;Core Vision Kit专注视觉处理,涵盖人脸检测、OCR等技术。文章还分析了两者的协同应用及生态发展趋势,展望未来AI技术与鸿蒙系统结合带来的智能交互新阶段。
240 31
|
6月前
|
搜索推荐 UED Python
实现一个带有昼夜背景切换的动态时钟:从代码到功能解析
本文介绍了一个使用Python和Tkinter库实现的动态时钟程序,具有昼夜背景切换、指针颜色随机变化及整点和半点报时功能。通过设置不同的背景颜色和随机变换指针颜色,增强视觉吸引力;利用多线程技术确保音频播放不影响主程序运行。该程序结合了Tkinter、Pygame、Pytz等库,提供了一个美观且实用的时间显示工具。欢迎点赞、关注、转发、收藏!
242 94
|
4月前
|
供应链 监控 搜索推荐
反向海淘代购独立站:功能解析与搭建指南
“反向海淘”指海外消费者购买中国商品的现象,体现了中国制造的创新与强大。国产商品凭借高性价比和丰富功能,在全球市场备受欢迎。跨境电商平台的兴起为“反向海淘”提供了桥梁,而独立站因其自主权和品牌溢价能力逐渐成为趋势。一个成功的反向海淘代购独立站需具备多语言支持、多币种支付、物流跟踪、商品展示、购物车管理等功能,并通过SEO优化、社交媒体营销等手段提升运营效果。这不仅助力中国企业开拓海外市场,还推动了品牌全球化进程。
141 19
|
4月前
|
SQL 运维 监控
高效定位 Go 应用问题:Go 可观测性功能深度解析
为进一步赋能用户在复杂场景下快速定位与解决问题,我们结合近期发布的一系列全新功能,精心梳理了一套从接入到问题发现、再到问题排查与精准定位的最佳实践指南。
|
4月前
|
算法 前端开发 定位技术
地铁站内导航系统解决方案:技术架构与核心功能设计解析
本文旨在分享一套地铁站内导航系统技术方案,通过蓝牙Beacon技术与AI算法的结合,解决传统导航定位不准确、路径规划不合理等问题,提升乘客出行体验,同时为地铁运营商提供数据支持与增值服务。 如需获取校地铁站内智能导航系统方案文档可前往文章最下方获取,如有项目合作及技术交流欢迎私信我们哦~
225 1
|
4月前
|
JSON 自然语言处理 前端开发
WebSocket调试工具深度对比:Postman与Apipost功能实测解析
本文深入对比了Postman与Apipost两款WebSocket调试工具。作为实时通讯系统工程师,作者在开发智能客服系统时遇到了传统工具调试复杂、文档管理不便的问题。通过引入Apipost的智能连接池、消息分组管理和自动化文档生成等功能,实现了多环境自动切换、消息分类和接口文档自动生成,极大提升了调试效率和团队协作效果。最终,使用Apipost使接口调试时间减少40%,文档维护成本降低70%,跨团队沟通效率提升50%。

热门文章

最新文章

推荐镜像

更多
  • DNS