window.requestAnimationFrame() 方法告訴瀏覽器您希望執(zhí)行動(dòng)畫,并請(qǐng)求瀏覽器調(diào)用指定的函數(shù)在下一次重繪之前更新動(dòng)畫蝶柿。該方法將在重繪之前調(diào)用的回調(diào)作為參數(shù)。如果你想做逐幀動(dòng)畫的時(shí)候资溃,你應(yīng)該用這個(gè)方法大莫。這就要求你的動(dòng)畫函數(shù)執(zhí)行會(huì)先于瀏覽器重繪動(dòng)作。通常來說拓瞪,被調(diào)用的頻率是每秒60次缴罗,但是一般會(huì)遵循W3C標(biāo)準(zhǔn)規(guī)定的頻率。如果是后臺(tái)標(biāo)簽頁(yè)面祭埂,重繪頻率則會(huì)大大降低愧薛。
瀏覽器的顯示頻率一般是16.7ms,我們將setTimeout的間隔時(shí)間設(shè)為16.7ms鼠哥,節(jié)奏會(huì)如下圖第一行展示 。但如果我們將間隔時(shí)間設(shè)為10ms矢空,那么節(jié)奏會(huì)如下圖第二行展示。
舉個(gè)例子:
國(guó)慶北京高速禀横,最多每16.7s通過一輛車屁药,結(jié)果,突然插入一批setTimeout的軍車柏锄,強(qiáng)行要10s通過酿箭。顯然,這是超負(fù)荷的趾娃,要想順利進(jìn)行缭嫡,只能讓第三輛車直接消失(正如顯示繪制第三幀的丟失)。然而抬闷,這是不現(xiàn)實(shí)的妇蛀,于是就有了會(huì)堵車!
同樣的笤成,顯示器16.7ms刷新間隔之前發(fā)生了其他繪制請(qǐng)求(setTimeout)评架,導(dǎo)致所有第三幀丟失,繼而導(dǎo)致動(dòng)畫斷續(xù)顯示(堵車的感覺)炕泳,這就是過度繪制帶來的問題纵诞。不僅如此,這種計(jì)時(shí)器頻率的降低也會(huì)對(duì)電池使用壽命造成負(fù)面影響培遵,并會(huì)降低其他應(yīng)用的性能浙芙。
這也是為何setTimeout的定時(shí)器值推薦最小使用16.7ms的原因(16.7 = 1000 / 60, 即每秒60幀)。
而requestAnimationFrame就是為了解決這個(gè)問題而出現(xiàn)的籽腕。它所做的事情很簡(jiǎn)單嗡呼,就是跟著瀏覽器的繪制走,如果瀏覽設(shè)備繪制間隔是16.7ms节仿,那它就在這個(gè)間隔繪制晤锥。如果瀏覽設(shè)備繪制間隔是10ms,它就10ms繪制廊宪。這樣就不會(huì)存在過度繪制的問題矾瘾,動(dòng)畫不會(huì)掉幀,播放自然流暢箭启。
兼容性:
統(tǒng)一的向下兼容方法:
(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));
var id = window.setTimeout(function() {
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
if (!window.cancelAnimationFrame) {
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}
}());