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. oracle语句录

    从表中选出一个某个单位最近的记录 select * from RSDL_SHXX where sbsj in (select max (sbsj) from RSDL_SHXX where DW_ID ...

  2. 堆排序python实现

    def MAX_Heapify(heap,HeapSize,root):#在堆中做结构调整使得父节点的值大于子节点 left = 2*root+1 right = left + 1 larger = ...

  3. 常见无线DOS攻击

    记录下自己最近一段时间对无线渗透学习的笔记. 无线DOS就是无线拒绝服务攻击.主要包括以下几种攻击类型:Auth Dos攻击.Deauth Flood攻击.Disassociate攻击及RF干扰攻击等 ...

  4. Python学习笔记第二十三周(Flask架构)

    目录: 一.变量引用 内容: 备注:PyCharm小技巧,comm+alt+l  自动修改格式,comm+alt+return  向上添加新行 一.变量引用 1.url生成 from flask im ...

  5. threejs linesegment的拾取实验

    通过对线段(图中的线段在绘图里,是一条线段)的拾取发现如下几个特点: 1)index表示一条线段的from向量index,即第几个分段: 2)线段空白的地方拾取不到(不属于线段上): 3)为何用多条分 ...

  6. 【leetcode】409. Longest Palindrome

    problem 409. Longest Palindrome solution1: class Solution { public: int longestPalindrome(string s) ...

  7. TFLearn 与 Tensorflow 一起使用

    好用的不是一点点..=-=.. import tensorflow as tf import tflearn import tflearn.datasets.mnist as mnist # Usin ...

  8. 九度OJ1111题-单词替换

    题目1111:单词替换 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6752 解决:1891 题目描述: 输入一个字符串,以回车结束(字符串长度<=100).该字符串由若干个单词组 ...

  9. 归并排序merge_sort

    将区间递归分解,直到区间只有2个元素,然后比较大小,排序,等递归回来的时候就将排序好的子区间再排序合并....一直排序合并,最后就排序完成了. (可以做范围大的逆序数的题) #include < ...

  10. numpy中的复合数组

    1.复合数组的创建 # 复合数组,最重要的是定义dtype a = np.array([('ABC', [1, 2, 3])], dtype="U3, 3i4") print(a) ...