• 定时器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)的更多相关文章

  1. HTML5探秘:用requestAnimationFrame优化Web动画

    本文转载自: HTML5探秘:用requestAnimationFrame优化Web动画

  2. [js高手之路] html5新增的定时器requestAnimationFrame实战进度条

    在requestAnimationFrame出现之前,我们一般都用setTimeout和setInterval,那么html5为什么新增一个requestAnimationFrame,他的出现是为了解 ...

  3. html5新增的定时器requestAnimationFrame

    在requestAnimationFrame出现之前,我们一般都用setTimeout和setInterval,那么html5为什么新增一个requestAnimationFrame,他的出现是为了解 ...

  4. React-Native 动画优化

    前言 动画对于客户端来说是非常重要的一部分,直接影响到应用的用户体验.前端对于动画优化通常使用CSS3样式来实现动画,以利用GPU加速特性.而React-Native由于渲染模式的不同,无法使用CSS ...

  5. 移动HTML5前端性能优化总结

    概述 1. PC优化手段在Mobile侧同样适用 2. 在Mobile侧我们提出三秒种渲染完成首屏指标 3. 基于第二点,首屏加载3秒完成或使用Loading 4. 基于联通3G网络平均338KB/s ...

  6. [js高手之路] html5 canvas动画教程 - 实时获取鼠标的当前坐标

    有了前面的canvas基础之后,现在开始就精彩了,后面写的canvas教程都是属于综合应用,前面已经写了常用的canvas基础知识,参考链接如下: [js高手之路] html5 canvas系列教程 ...

  7. [js高手之路]html5 canvas动画教程 - 边界判断与小球粒子模拟喷泉,散弹效果

    备注:本文后面的代码,如果加载了ball.js,那么请使用这篇文章[js高手之路] html5 canvas动画教程 - 匀速运动的ball.js代码. 本文,我们要做点有意思的效果,首先,来一个简单 ...

  8. [js高手之路]html5 canvas动画教程 - 边界判断与反弹

    备注:本文后面的代码,如果加载了ball.js,那么请使用这篇文章[js高手之路] html5 canvas动画教程 - 匀速运动的ball.js代码. 边界反弹: 当小球碰到canvas的四个方向的 ...

  9. 移动HTML5前端性能优化指南

    概述 1. PC优化手段在Mobile侧同样适用 2. 在Mobile侧我们提出三秒种渲染完成首屏指标 3. 基于第二点,首屏加载3秒完成或使用Loading 4. 基于联通3G网络平均338KB/s ...

随机推荐

  1. Javah提示未找到 ..的类

    Javah相关错误,如下图所示:

  2. selenium webdriver常用函数

    from selenium import webdriver driver = webdriver.Ie(executable_path = "e:\\IEDriverServer" ...

  3. linux编译gpu_flow

    因为需要做双流,论文里面推荐到这个GPU版本的TVL1算法,于是开始编译. 一.下载源码 git clone https://github.com/feichtenhofer/gpu_flow.git ...

  4. JRebel for IntelliJ

    好久没用jrebel了,跟前端进行项目联调总是有些许改动,还是热部署方便. 目前用的idea版本:IntelliJ IDEA 2019.2 JRebel插件版本:JRebel for IntelliJ ...

  5. java 与 c# 3des 加解密

    java 与 c# 3des 加解密   主要差异如下: 1.  对于待加密解密的数据,各自的填充模式不一样 C#的模式有:ANSIX923.ISO10126.None.PKCS7.Zero,而Jav ...

  6. Linux下高cpu解决方案(转载)

    Linux下高cpu解决方案(转载 1.用top命令查看哪个进程占用CPU高gateway网关进程14094占用CPU高达891%,这个数值是进程内各个线程占用CPU的累加值.   PID USER  ...

  7. ASP.NET Core 入门笔记6,ASP.NET Core MVC 视图传值入门

    摘抄自:https://www.cnblogs.com/ken-io/p/aspnet-core-tutorial-mvc-view-renderdata.html 如有侵权请告知 一.前言 1.本教 ...

  8. 关于Bootstrap Table使用生成冻结窗格的表格

    参考资料 : <JS组件系列——Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案> <http://issues.wenzhixin.net.cn/bootst ...

  9. 安装heat

    在控制节点上执行 controller-heat(){mysql -uroot -p${MYSQL_PASSWD} << EOF DROP DATABASE IF EXISTS heat; ...

  10. 配置nova服务使用ceph作为后端存储

    在ceph监视器上执行 1.创建pool池 为nova服务创建pool池(因为我只有一个OSD节点,所以要将副本数设置为1) ceph osd pool create nova-vms 32 ceph ...