深入理解定时器系列——被誉为神器的requestAnimationFrame
与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔。这有什么好处呢?为什么requestAnimationFrame被称为神器呢?本文将详细介绍H5新增的定时器requestAnimationFrame
引入
计时器一直是javascript动画的核心技术。而编写动画循环的关键是要知道延迟时间多长合适。一方面,循环间隔必须足够短,这样才能让不同的动画效果显得平滑流畅;另一方面,循环间隔还要足够长,这样才能确保浏览器有能力渲染产生的变化
大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是lOOOms/60,约等于16.6ms
而setTimeout和setInterval的问题是,它们都不精确。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行
requestAnimationFrame采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果
特点
【1】requestAnimationFrame会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
【2】在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量
【3】requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
使用
requestAnimationFrame的用法与settimeout很相似,只是不需要设置时间间隔而已。requestAnimationFrame使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。它返回一个整数,表示定时器的编号,这个值可以传递给cancelAnimationFrame用于取消这个函数的执行
requestID = requestAnimationFrame(callback);
//控制台输出1和0
var timer = requestAnimationFrame(function(){
console.log(0);
});
console.log(timer);//
cancelAnimationFrame方法用于取消定时器
//控制台什么都不输出
var timer = requestAnimationFrame(function(){
console.log(0);
});
cancelAnimationFrame(timer);
也可以直接使用返回值进行取消
var timer = requestAnimationFrame(function(){
console.log(0);
});
cancelAnimationFrame(1);
兼容
IE9-浏览器不支持该方法,可以使用setTimeout来兼容
if(!window.requestAnimationFrame){
var lastTime = 0;
window.requestAnimationFrame = function(callback){
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);
};
}
应用
现在分别使用setInterval、setTimeout和requestAnimationFrame这三个方法制作一个简单的进制度效果
【1】setInterval
<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
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);
}
</script>
【2】setTimeout
<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
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>
【3】requestAnimationFrame
<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
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);
}
});
}
</script>
深入理解定时器系列——被誉为神器的requestAnimationFrame的更多相关文章
- 深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame
× 目录 [1]引入 [2]特点 [3]使用[4]兼容[5]应用 前面的话 与setTimeout和setInterval不同,requestAnimationFrame不需要设置时间间隔.这有什么好 ...
- 深入理解定时器系列第一篇——理解setTimeout和setInterval
× 目录 [1]setTimeout [2]setInterval [3]运行机制[4]作用[5]应用 前面的话 很长时间以来,定时器一直是javascript动画的核心技术.但是,关于定时器,人们通 ...
- 深入理解JavaScript系列(结局篇)
介绍 最近几个月忙得实在是不可开交,终于把<深入理解JavaScript系列>的最后两篇“补全”了,所谓的全是不准确的,因为很多内容都没有写呢,比如高性能.Ajax安全.DOM详解.Jav ...
- 深入理解javascript系列(4):立即调用的函数表达式
本文来自汤姆大叔 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法 ...
- 深入理解javascript系列,读书笔记
深入理解JavaScript系列(2):揭秘命名函数表达式 1.讲了函数声明和函数表达式的区别,包括一些在函数提升上的区别 2.如果给函数表达式的函数也取名,会在调试的时候受益 3.不要在block( ...
- 深入理解JavaScript系列
转自http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html 深入理解JavaScript系列(1):编写高质量JavaScript代码 ...
- 深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点
深入理解JavaScript系列(1):编写高质量JavaScript代码的基本要点 2011-12-28 23:00 by 汤姆大叔, 139489 阅读, 119 评论, 收藏, 编辑 才华横溢的 ...
- [JS]深入理解JavaScript系列(4):立即调用的函数表达式
转自:汤姆大叔的博客 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行.在详细了解这个之前,我们来谈了解一下"自执行"这个叫法 ...
- 深入理解JavaScript系列(转自汤姆大叔)
深入理解JavaScript系列文章,包括了原创,翻译,转载,整理等各类型文章,如果对你有用,请推荐支持一把,给大叔写作的动力. 深入理解JavaScript系列(1):编写高质量JavaScript ...
随机推荐
- JAVA 各种数值类型最大值和最小值 Int, short, char, long, float,&nbs
转载地址:http://blog.sina.com.cn/s/blog_5eab3d430101fdv6.html 代码片段: fmax = Float.MAX_VALUE; fmin = Float ...
- Java将TXT上的数据转换成excel里面
package test; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; im ...
- Python全栈开发【模块】
Python全栈开发[模块] 本节内容: 模块介绍 time random os sys json & picle shelve XML hashlib ConfigParser loggin ...
- PDF虚拟打印机
1.安装福昕PDF阅读器,自己就会安装上PDF虚拟打印机 2.通过office2010之后版本中自带的另存为功能转换为pdf 3.pdf虚拟打印机工具:工具1:http://www.win2pdf.c ...
- SQL批量增加修改数据
insert into A表(字段1,字段2) select 字段1,字段2 From B表 [注:字段类型.字段数应相同] --批量进行修改ID值 declare @i int begin )) F ...
- maven学习(下)利用Profile构建不同环境的部署包
接上回继续,项目开发好以后,通常要在多个环境部署,象我们公司多达5种环境:本机环境(local).(开发小组内自测的)开发环境(dev).(提供给测试团队的)测试环境(test).预发布环境(pre) ...
- vue.js 接收url参数
1) 路由配置传参方式 在配置路由时 例如 "/firewall/authorize/:uid/:uname/:token" 页面url为 http://XXX.com/firew ...
- adb 的使用
打出log:adb logcat -s fliterName ps:(fliterName就是你的tag)
- php定界符<<<EOF讲解(转)
Heredoc技术.可用来输出大段的html和javascript脚本 1.PHP定界符的作用就是按照原样,包括换行格式什么的,输出在其内部的东西: 2.在PHP定界符中的任何特殊字符都不需要转义: ...
- Learn ES2015
折腾了大半年的项目,用的angular折腾快疯了. 总算有个小结了.正好闲下来为新的项目做准备,学点新的玩意玩玩,以往ES6都没用过,感觉被大部队甩好远了,抓紧跟上大部队的脚步... 1.利用let和 ...