1. requestAnimationFrame 概述

requestAnimationFrame 是浏览器用于定时循环操作的一个API, 类似于setTimeout, 主要用途是按帧对网页进行重绘.

设置这个API的目的就是为了让各种网页动画效果 (DOM动画, Canvas动画, SVG动画, WebGL动画) 能有一个统一的刷新机制, 从而节省系统资源, 提高系统性能, 改善视觉效果. 使用这个API, 就是告诉浏览器希望执行一个动画, 让浏览器在下一个动画帧对网页进行一次网页重绘.

requestAnimationFrame 的优势在于, 充分利用了显示器的刷新机制, 比较节省系统的资源, 显示器的固定刷新频率是 60HZ或者75HZ, 也就是说, 每秒最多能绘制60次或者75次, 这个API的思想就是与这个刷新频率保持同步, 利用这个刷新频率对网页进行重绘. 另外, 使用这个API, 当浏览器不处于当前标签页, 就会自动停止刷新.

缺点是, requestAniamtionFrame 是在主线程上完成的, 这就意味着, 一旦主线程非常繁忙, requestAnimationFrame的动画效果会大打折扣.

requestAnimationFrame 使用一个回调函数作为参数, 这个回调函数在流浪器重绘之前调用

var requestID = window.requestAnimationFrame(calback)

目前主要浏览器都支持这个API, 查看更多兼容性

即使主流浏览器都支持, 但还是要检查浏览器是否支持, 而且各浏览器都带有前缀, 如果不支持, 就使用setTimeout模拟该方法

window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();

上面的代码按照1秒60次来模拟requestAnimationFrame, 使用的时候只需要反复调用即可

function repeatOften() {
// Do whatever
requestAnimationFrame(repeatOften);
} requestAnimationFrame(repeatOften);

2. cancelAnimationFrame 方法

cancelAnimationFrame方法用于取消重绘

window.cancelAnimationFrame(requestID)

他的参数是requestAnimationFrame返回的一个代表任务ID的整数值

var globalID;

function repeatOften() {
$("<div />").appendTo("body");
globalID = requestAnimationFrame(repeatOften);
} $("#start").on("click", function() {
globalID = requestAnimationFrame(repeatOften);
}); $("#stop").on("click", function() {
cancelAnimationFrame(globalID);
});

上面的代码就是不断的网body中添加div, 知道用户点击stop为止

3. 实例

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>request</title>
<style type="text/css">
#anim {
height: 100px;
width: 100px;
border-radius: 6px;
background-color: #f66;
color: #fff;
margin-top: 50px;
position: absolute;
}
</style>
</head>
<body>
<div id="anim">运动区域</div>
<button id="start">开始</button>
<button id="stop">停止</button>
</body>
<script type="text/javascript">
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
window.setTimeout(callback, 1000 / 60);
};
})();
var anim = document.getElementById('anim');
var start = document.getElementById('start');
var stop = document.getElementById('stop');
var startTime = undefined;
var requestId = undefined;
function render(time) {
if (time === undefined) {
time = Date.now();
}
if (startTime === undefined) {
startTime = time;
}
anim.style.left = ((time - startTime) / 10 % 500) + 'px';
}
start.onclick = function() {
(function animloop() {
render();
requestId = requestAnimationFrame(animloop, anim)
})();
}
stop.onclick = function() {
window.cancelAnimationFrame(requestId);
}
</script>
</html>

在codepen看效果

下面看一个关于requestAnimationFrame的面试题

如何一次性加载几万条数据,要求不卡住界面?

道题考察了如何在不卡住页面的情况下渲染数据,也就是说不能一次性将几万条都渲染出来,而应该一次渲染部分 DOM,那么就可以通过 requestAnimationFrame 来每 16 ms 刷新一次。

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<ul>控件</ul>
<script>
setTimeout(() => {
// 插入十万条数据
const total = 100000
// 一次插入 20 条,如果觉得性能不好就减少
const once = 20
// 渲染数据总共需要几次
const loopCount = total / once
let count = 0
let requestId = 0
let ul = document.querySelector("ul");
function add() {
// 优化性能,插入不会造成回流
const fragment = document.createDocumentFragment();
for (let i = 0; i < once; i++) {
const li = document.createElement("li");
count += 1
li.innerText = Math.floor(count);
fragment.appendChild(li);
}
ul.appendChild(fragment);
loop();
}
function loop() {
if (count < total) {
requestId = window.requestAFrame(add);
} else {
window.cancelAFrame(requestId)
}
}
loop();
}, 0);
// handle multiple browsers for requestAnimationFrame()
window.requestAFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
// if all else fails, use setTimeout
function (callback) {
return window.setTimeout(callback, 1000 / 60); // shoot for 60 fps
};
})(); // handle multiple browsers for cancelAnimationFrame()
window.cancelAFrame = (function () {
return window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.oCancelAnimationFrame ||
function (id) {
window.clearTimeout(id);
};
})();
</script>
</body>
</html>

参考链接

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame

http://www.jb51.net/article/92994.htm

https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation

http://www.zhangxinxu.com/wordpress/2013/09/css3-animation-requestanimationframe-tween-%E5%8A%A8%E7%94%BB%E7%AE%97%E6%B3%95/

requestAnimationFrame 持续动画效果的更多相关文章

  1. 使用requestAnimationFrame做动画效果二

    3月是个好日子,渐渐地开始忙起来了,我做事还是不够细心,加上感冒,没精神,今天差点又出事了,做过的事情还是要检查一遍才行,哎呀. 使用requestAnimationFrame做动画,我做了很久,终于 ...

  2. 使用requestAnimationFrame做动画效果一

    最近学习了requestAnimationFrame,看了张鑫旭直白易懂,但是某些地方语言过于裸露的文章http://www.zhangxinxu.com/wordpress/2013/09/css3 ...

  3. window.requestAnimationFrame()的使用,处理更流畅的动画效果

    https://blog.csdn.net/w2765006513/article/details/53843169 window.requestAnimationFrame()的使用 2016年12 ...

  4. jquery动画效果中,避免持续反应用户的连续点击

    一.某些动画效果中,避免持续连续反应用户的连续点击(这标题真不好描述) 意思就是指用户点击速度很快,完成一次效果的时间不能很快结束的话,就会出现用户不点击了,效果还在持续.看下面例子就明白了,手风琴效 ...

  5. Android动画效果之自定义ViewGroup添加布局动画

    前言: 前面几篇文章介绍了补间动画.逐帧动画.属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢?今天结合自定义ViewGroup来学习一下布局动画.本文将通 ...

  6. Android动画效果之Frame Animation(逐帧动画)

    前言: 上一篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画),今天来总结下Android的另外一种动画Frame ...

  7. 详解用CSS3制作圆形滚动进度条动画效果

    主  题 今天手把手教大家用CSS3制作圆形滚动进度条动画,想不会都难!那么,到底是什么东东呢?先不急,之前我分享了一个css实现进度条效果的博客<CSS实现进度条和订单进度条>,但是呢, ...

  8. requestAnimationFrame制作动画:旋转风车

    在以往,我们在网页上制作动画效果的时候,如果是用javascript实现,一般都是通过定时器和间隔来实现的,出现HTML5之后,我们还可以用CSS3 的transitions和animations很方 ...

  9. tween.js是一款可生成平滑动画效果的js动画库。tween.js允许你以平滑的方式修改元素的属性值。它可以通过设置生成各种类似CSS3的动画效果。

    简要教程 tween.js是一款可生成平滑动画效果的js动画库.相关的动画库插件还有:snabbt.js 强大的jQuery动画库插件和Tweene-超级强大的jQuery动画代理插件. tween. ...

随机推荐

  1. CSS学习笔记-04 a标签-导航练习

    个人练习,各位大神勿笑  .. <!DOCTYPE html> <html lang="en"> <head> <meta charset ...

  2. 了解下webpack的几个命令

    [ webpack3.0.0刚刚出来  所以文章是跟着低版本 教程 操作熟悉  结果好多对不上喔] 六:了解下webpack的几个命令 webpack         // 最基本的启动webpack ...

  3. 再谈kbmMW垃圾回收

    很早就写了关于kbmMW Server如何实现的垃圾回收,但最近一段时间还是为此遇到问题,实现的Server不能稳定运行,发生问题后不响应客户端的查询请求,在客户端得到服务端返回地址错误信息,只能重启 ...

  4. debian镜像下载地址

     http://cdimage.debian.org/debian-cd/9.8.0-live/amd64/iso-hybrid/ 

  5. mail工具的安装、配置及问题处理

    使用mail发邮件时,应先将相关邮件服务启动,本文主要介绍sendmail邮件工具的配置方法和问题处理. 1.安装 ubuntu中sendmail函数可以很方便的发送邮件,ubuntu sendmai ...

  6. python短域名数据分析框架

    本文数据源及分析方法均参考<利用python进行数据分析>一书.但我重新对数据分析目标和步骤进行了组织,可以更加清晰的呈现整个挖掘分析流程. 分析对象为美国某短域名网站记录的短域名生成数据 ...

  7. python day04--列表,元祖

    一.列表增删改查 1.增----append() # lst = [1, True, "哈哈", ("可口可乐", "百事可乐", &quo ...

  8. Tail Recusive

    1.尾递归 double f(double guess){ if (isGoodEnough(guess)) return guess; else return f(improve(guess)); ...

  9. JAXB性能优化

    前言: 之前在查阅jaxb相关资料的同时, 也看到了一些关于性能优化的点. 主要集中于对象和xml互转的过程中, 确实有些实实在在需要注意的点. 这边浅谈jaxb性能优化的一个思路. 案列: 先来构造 ...

  10. sql数据查询基础笔记

    使用SELETE语句进行查询 语法 SELECT<列名> FROM<表名>  [ORDER BY <排序的列名>[ASC或DESC]] 1.查询所有的数据和列 SE ...