requestAnimationFrame
window.requestAnimationFrame() 这个方法是用来在页面重绘之前,通知浏览器调用一个指定的函数
相当一部分的浏览器的显示频率是16.7ms, 1m绘制60帧,就是上图第一行的节奏,表现就是“我和你一步两步三步四步往前走……”。如果我们火力搞猛一点,例如搞个10ms setTimeout,就会是下面一行的模样——每第三个图形都无法绘制(红色箭头指示),表现就是“我和你一步两步 坑 四步往前走……”。
requestAnimationFrame就是为了这个而出现的。我所做的事情很简单,跟着浏览器的绘制走,如果浏览设备绘制间隔是16.7ms,那我就这个间隔绘制;如果浏览设备绘制间隔是10ms, 我就10ms绘制。这样就不会存在过度绘制的问题,动画不会掉帧,自然流畅的说~~
(function() {
var lastTime = 0;
var vendors = ['webkit', 'moz'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || // Webkit中此取消方法的名字变了
window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) {
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16.7 - (currTime - lastTime));//上一次调用和下一次调用直接的间隔,timeToCall如果大于16.7就证明浏览器空闲没有在绘制,立刻插入执行绘制。timeToCall如果小于16.7。就用16.7减去上一次到这一次执行代码所用的实际。得到多少秒后可以插入执行。
var id = window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}());
调用requestAnimationFrame 一般都是递归调用实现绘制动画。
funFall = function() {
var start = 0, during = 100;
var _run = function() {
start++;
var top = Tween.Bounce.easeOut(start, objBall.top, 500 - objBall.top, during);
ball.css("top", top);
shadowWithBall(top); // 投影跟随小球的动
if (start < during) requestAnimationFrame(_run); //递归调用_run()就是每一次动画执行的代码。递归调用这个函数。requestAnimationFrame会根据浏览器绘制的频率进行调用。
};
_run();
};
var i = 0;
function aa() {
setTimeout(()=>{
i++
console.log(i)
},1)
if(i <= 11){
aa()
}
}
aa()
上面这个代码会造成死循环,为什么?
因为setTimeout是异步的,必须等待所有同步代码执行完成才会执行,这里的同步代码包括if(i <= 11){},但是i的值是在setTimeout才会被改变的。if这里的i就一直是0,所有造成了死循环,所有应该按照下面这种代码的逻辑书写。
function res (callback) {
setTimeout(callback, 1000 / 60)
}
const startD = 0
function move() {
console.log('sss');
if(startD >=5){
return;
}
startD++
res(()=> {move()})
}
move()
requestAnimationFrame
从微信小程序重力感应 API 到 requestAnimationFrame 探索实现
Javascript高性能动画与页面渲染