javascript动画、运动算法详细解释与分析 (二、javascript动画 时间精度问题)
三、时间精度问题
首先我们必须知道出现时间精度问题的原因。
如果你对javascript单线程机制不太熟悉,或者对setInterval、setTimeOut函数执行机制不太理解,希望你能先看一下这篇文章:How JavaScript Timers Work [Copy]。然后你可以看一下这篇文章http://icolin.org/javascript/settimeout-bug-in-ie-with-winxp.html。第一篇文章可以帮助你理解javascript单线程机制以及setInterval、setTimeOut函数的执行机制,第二篇文章中 iColin 童鞋已经对时间精度问题出现的情况作了详细的描述,他和我们在这里的问题是一样的,所以我就不再复述。最后一定要看 Omiga 的 再谈JavaScript时钟中的16ms精度问题 这篇文章。
(希望你确实看了那三篇文章,这样你才能更加容易的理解下面的内容)
那么现在相信你对问题出现的原因已经理解的差不多了,我在这里再做一下小结:
javascript动画在浏览器中运行的过程中会产生时间误差,误差由系统环境,浏览器环境,程序运算时间,以及其他人为原因造成(我们这里排除人为错误导致的误差)。那么系统环境包括计算机硬件、计算机操作系统,浏览器环境包括浏览器内核、javascript解释引擎等,程序运算时间虽然有时可以忽略,但程序却可能由于javascript的单线程机制造成时间延迟。所以如果想把时间精确到毫秒,那是很有难度的,jQuery也考虑到了这个问题,所以她采用了消息队列机制来尽量的消除这种误差,不过效果差强人意。因为程序本身的时间精度就很难控制,所以如果使用程序本身来控制时间精度,那就好像拿油灭火。。。因为有很多不可抗力因素和外力因素影响。所以我们暂且将动画时间精确到秒。
这里对时间精度问题的讨论就先到这里,如果你有更好的解决方案,非常非常希望你能给予指导,非常非常感谢。
在这里我们顺便顺便解释一下上次遗留的 (这里为什么是以6px/30ms的速度等下解释) 这个问题。
首先要说一下Tween算法,我是从 cloudgamer 的 http://www.cnblogs.com/cloudgamer/archive/2009/01/06/tween.html这篇文章中看到了Tween算法,进而在 robertpenner 的《Flash_MX编程与创意实现》中看到的非常细致的讲解。网址: http://www.robertpenner.com/easing/ 。如果想搞Flash创意和动画的朋友推荐看这本书,我看了一部分,讲得不错,网上对这本书的评论也很好,我这里有PDF中文版的,需要的跟我联系。
在Flash中,动画时长都是以帧为单位来计算的。每帧时长*帧数就是动画总时间。在我们javascript中,我们的帧时长实际上就是setInterval、setTimeOut的第二个参数。而帧数就是
1: Math.prototype.linearTween = function( t, b, c, d){2: return t*c/d + b;3: }
上面linear算法中的d和t(d表示总帧数,t表示已经经过的帧数)。
所以如果你就像最开始那样单纯的认为t是时间,可能你就会陷入像我一样的痛苦的迷茫中,半天不能自拔。我们再来复习一下这段代码。
1: $ = function( id ){ return typeof id == "string"?document.getElementById(id):id }2:
3: /* des:tween算法。4: t: 动画已经执行的时间(实际上时执行多少次/帧数)5: b: 起始位置6: c: 终止位置7: d: 从起始位置到终止位置的经过时间(实际上时执行多少次/帧数)*/8: tween = {
9: linear : function( t, b, c, d){10: return t*c/d + b;11: }
12: }
13:
14: move={
15: moveType : function(mvTp){return mvTp && typeof(mvTp)== ”string” && tween[mvTp] ? mvTp: "linear" },16:
17: startMove : function( mvObj,mvTp,t,b,c,d ){18: t ? t : t=0; b ? b : b = 0; c ? c : c =300; d ? d : d = 50;
19: $(mvObj).style.position =="relative" || $(mvObj).style.position =="absolute"20: ? 1 : $(mvObj).style.position = "relative";21: //每隔30毫秒重复执行改变元素位置的函数22: mvTimer = setInterval(function(){23: //判断动画已经执行的时间(次数/帧数)是否小于总时间,是的话继续执行改变位置的函数,否则的话,清理该interval。24: t <= d
25: ? function(){ $(mvObj).style.left = parseInt(tween[move.moveType(mvTp)](t,b,c,d))+"px"; t++;}()26: : clearInterval(mvTimer);
27: } ,30 )
28: }
29: }
30:
31: move.startMove("moveLinear");在这里我们动画的帧数是d=50,经过帧数为t,当t<=d时,继续执行动画,每帧的时间间隔是30毫秒,该元素将从距离窗口左边距为0的位置移动到距离窗口左边距为300的位置(这里忽略body的默认margin)。
今天先到这里,下次将会接着分析Tween算法,我将尽最大努力来经历这个有意思的东西。