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. poj3279(dfs+二进制枚举思路)

    题意转载自https://www.cnblogs.com/blumia/p/poj3279.html 题目属性:DFS 相关题目:poj3276 题目原文:[desc]Farmer John know ...

  2. [Paper] Selection and replacement algorithm for memory performance improvement in Spark

    Summary Spark does not have a good mechanism to select reasonable RDDs to cache their partitions in ...

  3. 数据分析常用的python工具和SQL语句

    select symbol, "price.*" from stocks :使用正则表达式来指定列查询 select count(*), avg(salary) from empl ...

  4. 漫步Java------接口

    接口 一.定义 具有相同行为(方法),但是不相关的类 二.特点 只是提供方法,不定义方法的具体实现. 一个类只能继承一个父类,但是接口却可以继承多个接口. 接口是一个引用类型的变量 接口没有构造方法, ...

  5. 2017年3月1日09:45:39 css选择器,session数据取不到

    昨天碰到了一个问题,通过输入指定的url进行登录在服务端将url存在session中但是登陆之后因为页面提交的登录请求是ajax请求,在后端提取session时获取不当之前存的url,老司机说不是同一 ...

  6. REST easy with kbmMW #20 – OpenAPI and Swagger UI

    即将推出的kbmMW更新不仅是一些bug修正,同时将包含一个新的主要功能:客户端存根生成器框架. 那什么是客户端存根生成器框架呢? 他是一个基于kbmMW smart services,可以生成由各种 ...

  7. springboot (spring mvc)集成swagger

    最近用springboot构建rest接口,考虑到最方便的验证接口,想到了引入swagger. 基本的步骤大致如下: 1.pom中引入swagger依赖: <dependency> < ...

  8. HDU 1205 吃糖果(想想题)

    题目传送:http://acm.hdu.edu.cn/showproblem.php?pid=1205 Problem Description HOHO,终于从Speakless手上赢走了所有的糖果, ...

  9. Spring Boot 揭秘与实战(五) 服务器篇 - 内嵌的服务器 Tomcat剖析

    文章目录 1. 内嵌的 Tomcat,一个Jar包运行 2. 如何定制内嵌 Tomcat3. War 包部署的使用细节 2.1. 设置内嵌Tomcat的端口 2.2. 设置内嵌Tomcat的最大线程数 ...

  10. busybox devmem 直接获取、修改内存信息

    /********************************************************************** * busybox devmem 直接获取.修改内存信息 ...