背景

在Web应用中,实现动画效果的方法比较多,Javascript 中可以通过定时器 setTimeout或者setInterval 来实现,css3 可以使用 transition 和 animation 来实现,html5 中的 canvas 也可以实现。除此之外,html5 还提供一个专门用于请求动画的API,那就是 requestAnimationFrame,顾名思义就是请求动画帧。

但是传统的通过setTimeout或者setInterval实现的动画,存在两个问题,第一个就是动画的循时间环间隔不好确定,设置长了动画显得不够平滑流畅, 设置短了浏览器的重绘频率会达到瓶颈,推荐的最佳循环间隔是17ms(大多数电脑的显示器刷新频率是60Hz,1000ms / 60),第二个问题是定时器第二个时间参数只是指定了多久后将动画任务添加到浏览器的UI线程队列中,如果UI线程处于忙碌状态,那么动画不会立刻执行,为了解决这个问题,H5中加入了requestAnimationFrame。

setInterval实现一个动画

<html>
<head>
<title></title>
<style type="text/css">
#box {
margin: 200px;
width: 200px;
height: 200px;
background: green;
}
</style>
</head> <body>
<div id="box"></div>
</body>
<script type="text/javascript">
var element = document.getElementById('box')
var left = 0;
var animateCallback = function() {
element.style.marginLeft = (++left)+ 'px';
if (left === 500) {
clearInterval(interval);
}
}
var interval = setInterval(animateCallback, (1000 / 60));
</script>
使用setInterval我们成功的实现了一个平滑的动画效果,但是我们会发现setInterval的执行时间并不确定,在javascript中,setInterval任务被放进了异步队列中,只有当主线程上的任务执行完以后,才会去检查该队列里的任务是否需要开始执行,所以setInterval的实际执行时机一般要比其设定的时间晚一些。使用setInterval实现动画容易失帧。

丢帧

例如我们使用setInterval进行颜色的切换

var color = ['green', 'red', 'blue', 'yellow'];
var element = document.getElementById('box');
var index = 0;
var animateCallback = function() {
index++;
element.style.backgroundColor = color[index];
if (index === 3){
clearInterval(interval);
}
}
var interval = setInterval(interval, 1000 / 100);

上面的动画切换我们设置了间隔10切换一次,但是此时的屏幕刷新频率为16.7,

  1. 第0ms时,屏幕未刷新,等待中,setInterval也未执行,等待中;
  2. 第10ms时,屏幕未刷新,等待中,setInterval执行颜色切换为green
  3. 第16.7ms时: 屏幕刷新,屏幕的box颜色改变为green,setInterval未执行。继续等待
  4. 第20ms时:屏幕未刷新,等待中,setInterval执行颜色切换为red,
  5. 第30ms时,屏幕未刷新,等待中,setInterval执行颜色切换为blue,
  6. 第34.7ms时,屏幕刷新,屏幕的box颜色改变为blue,setTimeout未执行,继续等待中。
  7. ...
从上面的执行过程中,我们可以看出,在执行到20ms和30ms直接,setInterval切换了两次颜色,但是屏幕并没有执行一次刷新,就会出现,在34.7ms时,屏幕上直接展示的就是blue颜色,而跳过了red颜色。这就是丢帧现象,这种现象也会引起页面卡顿。

requstAnimationFrame实现

<html>
<head>
<title></title>
<style type="text/css">
#box {
margin: 200px;
width: 200px;
height: 200px;
background: green;
}
</style>
</head> <body>
<div id="box"></div>
</body>
<script type="text/javascript">
var start = null;
var element = document.getElementById('box');
var left = 0;
var raf_id = null;
function animateCallback() {
element.style.marginLeft = (++left) + 'px';
if (left === 500) {
cancelAnimationFrame(raf_id);
} else {
raf_id = requestAnimationFrame( animateCallback );
}
}
raf_id = window.requestAnimationFrame(animateCallback);
</script>
requestAnimationFrame返回请求的id(整数),我们可以使用这个id来取消请求(cancelAnimationFram(id)),从而停止动画的执行。 和setInterval相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机,requestAnimationFrame的步伐跟着系统的刷新步伐走,它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧。

requestAnimationFrame优势

CPU节能

使用setTimeout实现的动画,当页面被隐藏或最小化时,setTimeout仍然在后台执行动画任务,此时页面处于不可见或者不可用的状态,刷新动画是没有意义的,而且还浪费CPU资源,而rAF则完全不同,当页面处于未激活的状态下,该页面的屏幕绘制任务也会被系统暂停,因此跟着系统步伐走的rAF也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了CPU开销。

函数节流

在高频率事件(resize, scroll)中,为了防止在一个刷新间隔内发生多次函数执行,使用rAF可保证每次绘制间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销,一个绘制间隔内函数执行多次是没有意义的,因为显示器每16.7ms绘制一次,多次绘制并不会在屏幕上体现出来。

requestAnimationFrame小结的更多相关文章

  1. 关于 requestAnimationFrame 小结

    一.小谈 requestAnimationFrame: 说起 requestAnimationFrame,我们先看幅图: 相当一部分的浏览器的显示频率是16.7ms, 就是上图第一行的节奏,表现就是“ ...

  2. 3月web前端面试小结

    说一下box-sizing的应用场景 box-sizing的属性值分为两个,border-box和content-box,其中, border-box:width=content+padding+bo ...

  3. 神奇的requestAnimationFrame解决传统定时器bug

    可能你还没见过这个东西是个啥,其实他就是类似于setTimeout和setInterval,然而它与setTimeout和setInterval又有所不同,requestAnimationFrame不 ...

  4. 小程序刷新webview小结

    场景 在小程序其它页面做了操作,数据发生改变,回到webview页面时需要更新webview里面的数据.由于小程序没有提供与webview的实时通信能力,因此刷新页面是个可考虑的做法. 方法一 最常见 ...

  5. 动画requestAnimationFrame

    前言 在研究canvas的2D pixi.js库的时候,其动画的刷新都用requestAnimationFrame替代了setTimeout 或 setInterval 但是jQuery中还是采用了s ...

  6. 从零开始编写自己的C#框架(26)——小结

    一直想写个总结,不过实在太忙了,所以一直拖啊拖啊,拖到现在,不过也好,有了这段时间的沉淀,发现自己又有了小小的进步.哈哈...... 原想框架开发的相关开发步骤.文档.代码.功能.部署等都简单的讲过了 ...

  7. Python自然语言处理工具小结

    Python自然语言处理工具小结 作者:白宁超 2016年11月21日21:45:26 目录 [Python NLP]干货!详述Python NLTK下如何使用stanford NLP工具包(1) [ ...

  8. java单向加密算法小结(2)--MD5哈希算法

    上一篇文章整理了Base64算法的相关知识,严格来说,Base64只能算是一种编码方式而非加密算法,这一篇要说的MD5,其实也不算是加密算法,而是一种哈希算法,即将目标文本转化为固定长度,不可逆的字符 ...

  9. iOS--->微信支付小结

    iOS--->微信支付小结 说起支付,除了支付宝支付之外,微信支付也是我们三方支付中最重要的方式之一,承接上面总结的支付宝,接下来把微信支付也总结了一下 ***那么首先还是由公司去创建并申请使用 ...

随机推荐

  1. windows下用pip安装库,出现Command "python setup.py egg_info"错误信息

    转自:http://blog.csdn.net/u011092188/article/details/64123561 解决方案: python -m pip install --upgrade -- ...

  2. ROS代码经验系列-- tf进行位置查询变换

    include文件: #include "tf/transform_broadcaster.h" #include "tf/transform_listener.h&qu ...

  3. 容器编排系统K8s之Pod Affinity

    前文我们了解了k8s上的NetworkPolicy资源的使用和工作逻辑,回顾请参考:https://www.cnblogs.com/qiuhom-1874/p/14227660.html:今天我们来聊 ...

  4. JSF学习实战

    JSF是什么? JSF(JavaServer Faces)它是一个基于服务器端组件的用户界面框架. 它用于开发Web应用程序.它提供了一个定义良好的编程模型,由丰富的API和标签库组成.JSF API ...

  5. redhat_快捷键和shell命令操作.md

    tab键 命令自动补全 history !n 执行历史记录第n条 !! 执行上一条命令 !l 最后一条以l开头的命令 alias 创建命令的别名 alias 命令别名 = "命令行" ...

  6. Go 的定时任务模块 Cron 使用

    前言 新项目是Golang作为开发语言, 遇到了些新的坑, 也学到了新的知识, 收获颇丰 本章介绍在Go中使用Cron定时任务模块来实现逻辑 正文 在项目中, 我们往往需要定时执行一些逻辑, 举个例子 ...

  7. 【Linux】自建回收站

    linux rm命令是即刻删除的,而且挺多人喜欢加上-f强制命令,更暴力的是删除文件夹直接 rm -rf ,这样子代表你执行完后,就完全被干掉了. 还是推荐在linux下设置回收站,写一个shell脚 ...

  8. 此流非彼流——Stream详解

    Stream是什么? Java从8开始,不但引入了Lambda表达式,还引入了一个全新的流式API:Stream API.它位于java.util.stream包中. Stream 使用一种类似用 S ...

  9. Java中的NIO进阶

    目录 前言 NIO与多线程 Readable和Writeable的空触发 请求与返回的处理 事件的处理机制 NIO多线程使用的一个例子 前言 之前一篇文章简单介绍了NIO,并附了一个简单的例子,但是自 ...

  10. VKM5对应的BAPI或者函数

    在业务上,当一个交货单创建后,可能需要使用事物VKM5进行批准(解冻)才能做后续的捡配,发货过账等操作,通过搜索引擎发现,很多人也都会问是否有对应的bapi或者函数,替代VKM5,能够自开发程序进行批 ...