背景

在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. 3. Longest Substring Without Repeating Characters寻找不重复的最大子串

    首先弄清楚Substring和Subsequence,前者是子串,要求连续,后者是子序列,可以不连续 public int lengthOfLongestSubstring(String s) { / ...

  2. LVS之1---工作原理

    LVS之1---工作原理 LVS 介绍 LVS:Linux Virtual Server,Linux虚拟服务器,负载调度器,是一个由章文嵩(花名 正明)博士从1998年开始发起的自由软件项目. 软件作 ...

  3. docker获取Let's Encrypt永久免费SSL证书

    一 起因 官方的cerbot太烦了,不建议使用 还不如野蛮生长的acme.sh,而这里介绍docker运行cerbot获取Let's Encrypt永久免费SSL证书 二 选型 cerbot的证书不会 ...

  4. Head First 设计模式 —— 03. 装饰器 (Decorator) 模式

    思考题 有如下类设计: 如果牛奶的价钱上扬,怎么办?新增一种焦糖调料风味时,怎么办? 造成这种维护上的困难,违反了我们之前提过的哪种设计原则? P82 取出并封装变化的部分,让其他部分不收影响 多用组 ...

  5. 初学VBA

    一个最基本的VBA程序 Sub test() //宏开始 Dim ge As Range //定义变量 For Each ge In Range("a1:a10") //从a1到a ...

  6. 自定义 简单 底部tab

    项目地址:https://gitee.com/jielov/music-netease-api.git 先创建三个页面 分别为 home.vue , classify.vue, my.vue . 以下 ...

  7. Promise入门到精通(初级篇)-附代码详细讲解

    Promise入门到精通(初级篇)-附代码详细讲解 ​     Promise,中文翻译为承诺,约定,契约,从字面意思来看,这应该是类似某种协议,规定了什么事件发生的条件和触发方法. ​     Pr ...

  8. .NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ Masstransit 介绍)--学习笔记

    2.6.6 RabbitMQ -- Masstransit 介绍 Masstransit 是什么 Quickstart 消息 Message Masstransit 是什么 Masstransit 是 ...

  9. 【JavaWeb】JSON 文件

    JSON 文件 什么是 JSON JSON(JavaScript Object Notation),即 JS 对象符号. 是一种轻量级(相对于 XML 来说)的数据交换格式,易于阅读和编写,同时也易于 ...

  10. Python找对称数——纪念第一次自主编写代码

    2021-01-17 题目: [问题描述]已知10个四位数输出所有对称数及个数 n,例如1221.2332都是对称数[输入形式]10个四位数,以空格分隔开[输出形式]输入的四位数中的所有对称数,对称数 ...