HTML5之动画优化(requestAnimationFrame)
- 定时器setInterval实现的匀速动画为什么不是匀速?
- window.requestAnimationFrame()
一、定时器setInterval实现的匀速动画为什么不是匀速?
以上提问并非通过计算时间戳来计算每帧运动,而是直接使用定时器按照既定的间隔时间叠加每次运动距离的方式,这里主要意在解析浏览器中定时器与页面重绘导致的不准确性,先来看一个示例:
<style>
#a{
width: 100px;
height: 100px;
background-color:#faf;
position: absolute;
}
</style>
<div id="a"></div>
<script>
var aDom = document.getElementById('a');
function move(){
aDom.style.left = aDom.offsetLeft + 100 + 'px';
if(aDom.offsetLeft > 800){
clearInterval(timer);
}
}
var timer = setInterval(move,10);
</script>
示例中定时器每隔10毫秒元素移动100px,从定时器的意义上来说这就是匀速运动了,但是定时器只能每隔10毫秒将每一次运动的执行函数添加执行队列中,执行并修改元素的属性值,但是实际呈现到页面的却是1秒钟刷新60次的重绘来完成的,这种时间差会产生什么问题呢?
如果不了解浏览器js线程的话,建议有必要先了解:浏览器UI多线程及JavaScript单线程运行机制的理解
继续来看下面的分析:
第一次运动点:100px —— 实际运动(渲染到页面)的时间:16.667毫秒 —— 实际修改元素属性值的时间10毫秒;
第二次运动点:300px —— 实际运动(渲染到页面)的时间:33.334毫秒 —— 实际修改元素属性值的时间20毫秒(200px),实际修改元素属性值的时间30毫秒(300px);
第三次运动点:500px —— 实际运动(渲染到页面)的时间:50.001毫秒 —— 实际修改元素属性值的时间40毫秒(400px),实际修改元素属性值的时间50毫秒(500px);
第四次运动点:600px —— 实际运动(渲染到页面)的时间:66.668毫秒 —— 实际修改元素属性值的时间60毫秒(600px);
第五次运动点:800px —— 实际运动(渲染到页面)的时间:83.335毫秒 —— 实际修改元素属性值的时间70毫秒(700px),实际修改元素属性值的时间80毫秒(800px);
通过上面的分析,原本以定时器的执行逻辑,应该运动8次匀速到达终点的动画,实际上使用了5次非匀速的方式到达终点。
基于以上的原因我们在实现动画的时候采用的是执行时间比值的方式来实现元素运动:
var h = (new Date()).getTime(); //记录初始时间戳
var ratio = null;
var speed = null;
var t = setInterval(function(){
var performH = (new Date()).getTime(); //获取当前时间戳
ratio = (performH -h) / 80; //当前所用时间 / 动画执行实行
speed = ratio * 800; //使用时间比值计算得出当前元素运动位置
if(ratio < 1){
aDom.style.left = speed + "px";
}else{
aDom.style.left = 800 + "px";
clearInterval(t);
}
},1000/60);
这种处理方式理论上最接近匀速运动,但是还是会受js执行栈与浏览器重绘渲染速率的影响,在HTML5中提供window.requestAnimationFrame()这个API来解决这个问题,既然是HTML5就必然会有兼容性问题,下一节来具体分析。
二、window.requestAnimationFrame()
MDN手册:https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame#Notes
window.requestAnimationFrame()告诉浏览器希望执行一次动画,并要求浏览器在下次重绘之前调用指定的回调函数更新动画。
//语法
window.requestAnimationFrame(callback);
callback(回调函数):浏览器下次重绘前执行,callback执行时window.requestAnimationFrame()内部会给这个回调函数传入DOMHighResTimeStamp参数,DOMHighResTimeStamp参数指示当前被requesAnimationFrame排序的回调函数被触发时间。可以理解为时间戳,以ms(毫秒)为单位。
//上面的示例基于requestAnimationFrame实现
var startA = null;
function a(timestamp){
if(!startA) startA = timestamp;
var progress = timestamp - startA;
console.log(progress);
aDom.style.left = Math.min(progress / 80 * 800, 800) + 'px';
if(progress < 80){
window.requestAnimationFrame(a);
}
}
window.requestAnimationFrame(a);
window.requestAnimationFrame()是HTML5的API就必然会有兼容性问题:

封装兼容性的window.requestAnimationFrame():
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000/60);
}
})();
即使使用setInterval()来实现兼容,但并不代表其具备requestAnimationFrame()精准性。window.requestAnimationFrame()执行后会返回一个long整数,请求ID,是回调列表中唯一的标识。非零值,可以使用这个值来给window.cancelAnimationFrame()取消回调函数。
兼容window.cancelAnimationFrame():
window.cancelAnimFrame = (function(){
return window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
function(id){
window.clearTimeout(id);
}
})();
HTML5之动画优化(requestAnimationFrame)的更多相关文章
- HTML5探秘:用requestAnimationFrame优化Web动画
本文转载自: HTML5探秘:用requestAnimationFrame优化Web动画
- [js高手之路] html5新增的定时器requestAnimationFrame实战进度条
在requestAnimationFrame出现之前,我们一般都用setTimeout和setInterval,那么html5为什么新增一个requestAnimationFrame,他的出现是为了解 ...
- html5新增的定时器requestAnimationFrame
在requestAnimationFrame出现之前,我们一般都用setTimeout和setInterval,那么html5为什么新增一个requestAnimationFrame,他的出现是为了解 ...
- React-Native 动画优化
前言 动画对于客户端来说是非常重要的一部分,直接影响到应用的用户体验.前端对于动画优化通常使用CSS3样式来实现动画,以利用GPU加速特性.而React-Native由于渲染模式的不同,无法使用CSS ...
- 移动HTML5前端性能优化总结
概述 1. PC优化手段在Mobile侧同样适用 2. 在Mobile侧我们提出三秒种渲染完成首屏指标 3. 基于第二点,首屏加载3秒完成或使用Loading 4. 基于联通3G网络平均338KB/s ...
- [js高手之路] html5 canvas动画教程 - 实时获取鼠标的当前坐标
有了前面的canvas基础之后,现在开始就精彩了,后面写的canvas教程都是属于综合应用,前面已经写了常用的canvas基础知识,参考链接如下: [js高手之路] html5 canvas系列教程 ...
- [js高手之路]html5 canvas动画教程 - 边界判断与小球粒子模拟喷泉,散弹效果
备注:本文后面的代码,如果加载了ball.js,那么请使用这篇文章[js高手之路] html5 canvas动画教程 - 匀速运动的ball.js代码. 本文,我们要做点有意思的效果,首先,来一个简单 ...
- [js高手之路]html5 canvas动画教程 - 边界判断与反弹
备注:本文后面的代码,如果加载了ball.js,那么请使用这篇文章[js高手之路] html5 canvas动画教程 - 匀速运动的ball.js代码. 边界反弹: 当小球碰到canvas的四个方向的 ...
- 移动HTML5前端性能优化指南
概述 1. PC优化手段在Mobile侧同样适用 2. 在Mobile侧我们提出三秒种渲染完成首屏指标 3. 基于第二点,首屏加载3秒完成或使用Loading 4. 基于联通3G网络平均338KB/s ...
随机推荐
- 性能分析 | JVM发生内存溢出的8种原因及解决办法
推荐阅读:史上最详细JVM与性能优化知识点综合整理 1.Java 堆空间 2.GC 开销超过限制 3.请求的数组大小超过虚拟机限制 4.Perm gen 空间 5.Metaspace 6.无法新建本机 ...
- HttpURLConnection获取数据
使用步骤: 1.创建Url 2.用Url打开连接 3.设置请求参数 4. 获取响应状态码 2xxx 请求成功 3xxx重定向 4xxx资源错误 5xxx服务器错误 5.获取服务器返回的二进制输入流 6 ...
- Dubbo架构与底层实现
一.Dubbo的设计角色 (1)系统角色Provider: 暴露服务的服务提供方.Consumer: 调用远程服务的服务消费方.Registry: 服务注册与发现的注册中心.1Monitor: 统计服 ...
- 由DBCursor的“can't switch cursor access methods”异常引发的思考
先谈谈我是怎么用的: DBCollection dbcollection = XXXXXXXXXX(); //连接mongo DBCursor dbCursor = mergeVideoDB.find ...
- Java集合(4):未获支持的操作及UnsupportedOperationException
执行各种添加和移除的方法在Collection中都是可选操作的,这意味着实现类并不需要为这些方法提供实现.当我们调用这些方法时,将不会执行有意义的行为,而是通常抛出UnsupportedOperati ...
- 20190603 - CentOS 7 提示 Failed to load SELinux policy. Freezing 导致卡住不启动的解决办法
现象 最近 Windows 和两台 Mac 混用,将 Windows VirtualBox 中安装的 CentOS 7 拷贝到 Mac 上. 启动 CentOS 7 时,图形界面进度卡在最后,按 Es ...
- fdisk中参数配置说明表
命令 描述 a 设置活动分区标志 b 编辑BSD Unix系统用的磁盘标签 c 设置DOS兼容标志 d 删除分区 l 显示可用的分区类型 m 显示命令选项(帮助) n 添加一个新的分区 o 创建DOS ...
- FUZZ测试简介
基本思想:利用黑盒方法,发送大量恶意/随机数据到被测试系统,通过监视系统运行过程中的异常,来发现应用程序中可能存在的安全问题.
- SQuirreL连接Phoenix报java.util.concurrent.TimeoutException
1.表象 java.util.concurrent.TimeoutException at java.util.concurrent.FutureTask.get(FutureTask.java:20 ...
- Android ConstraintLayout 说明和例子
快速说明 当我们点击一个按钮时,显示效果如下 Baseline的显示需要右键该控件,然后 约束类型 尺寸约束 实心方块,用来调整组件的大小 边界约束 空心圆圈,建立组件之间,组件和parent的约束关 ...