深刻理解定時器系列——被譽爲神器的requestAnimationFrame

  與setTimeoutsetInterval不一樣,requestAnimationFrame不須要設置時間間隔。這有什麼好處呢?爲何requestAnimationFrame被稱爲神器呢?本文將詳細介紹H5新增的定時器requestAnimationFramejavascript

 

引入

  計時器一直是javascript動畫的核心技術。而編寫動畫循環的關鍵是要知道延遲時間多長合適。一方面,循環間隔必須足夠短,這樣才能讓不一樣的動畫效果顯得平滑流暢;另外一方面,循環間隔還要足夠長,這樣才能確保瀏覽器有能力渲染產生的變化html

  大多數電腦顯示器的刷新頻率是60Hz,大概至關於每秒鐘重繪60次。大多數瀏覽器都會對重繪操做加以限制,不超過顯示器的重繪頻率,由於即便超過那個頻率用戶體驗也不會有提高。所以,最平滑動畫的最佳循環間隔是lOOOms/60,約等於16.6msjava

  而setTimeout和setInterval的問題是,它們都不精確。它們的內在運行機制決定了時間間隔參數實際上只是指定了把動畫代碼添加到瀏覽器UI線程隊列中以等待執行的時間。若是隊列前面已經加入了其餘任務,那動畫代碼就要等前面的任務完成後再執行瀏覽器

  requestAnimationFrame採用系統時間間隔,保持最佳繪製效率,不會由於間隔時間太短,形成過分繪製,增長開銷;也不會由於間隔時間太長,使用動畫卡頓不流暢,讓各類網頁動畫效果可以有一個統一的刷新機制,從而節省系統資源,提升系統性能,改善視覺效果函數

 

特色

  【1】requestAnimationFrame會把每一幀中的全部DOM操做集中起來,在一次重繪或迴流中就完成,而且重繪或迴流的時間間隔牢牢跟隨瀏覽器的刷新頻率post

  【2】在隱藏或不可見的元素中,requestAnimationFrame將不會進行重繪或迴流,這固然就意味着更少的的cpu,gpu和內存使用量性能

  【3】requestAnimationFrame是由瀏覽器專門爲動畫提供的API,在運行時瀏覽器會自動優化方法的調用,而且若是頁面不是激活狀態下的話,動畫會自動暫停,有效節省了CPU開銷優化

 

使用

  requestAnimationFrame的用法與settimeout很類似,只是不須要設置時間間隔而已。requestAnimationFrame使用一個回調函數做爲參數,這個回調函數會在瀏覽器重繪以前調用。它返回一個整數,表示定時器的編號,這個值能夠傳遞給cancelAnimationFrame用於取消這個函數的執行動畫

requestID = requestAnimationFrame(callback); 
//控制檯輸出1和0
var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
console.log(timer);//1

  cancelAnimationFrame方法用於取消定時器spa

//控制檯什麼都不輸出
var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
cancelAnimationFrame(timer);

  也能夠直接使用返回值進行取消

var timer = requestAnimationFrame(function(){
    console.log(0);
}); 
cancelAnimationFrame(1);

 

兼容

  IE9-瀏覽器不支持該方法,可使用setTimeout來兼容

if(!window.requestAnimationFrame){
    var lastTime = 0;
    window.requestAnimationFrame = function(callback){
        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);
    };
}

 

應用

  如今分別使用setInterval、setTimeout和requestAnimationFrame這三個方法制做一個簡單的進制度效果

【1】setInterval

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
btn.onclick = function(){
    clearInterval(timer);
    myDiv.style.width = '0';
    timer = setInterval(function(){
        if(parseInt(myDiv.style.width) < 500){
            myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';
            myDiv.innerHTML =     parseInt(myDiv.style.width)/5 + '%';    
        }else{
            clearInterval(timer);
        }        
    },16);
}
</script>

 

【2】setTimeout

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
btn.onclick = function(){
    clearTimeout(timer);
    myDiv.style.width = '0';
    timer = setTimeout(function fn(){
        if(parseInt(myDiv.style.width) < 500){
            myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';
            myDiv.innerHTML =     parseInt(myDiv.style.width)/5 + '%';
            timer = setTimeout(fn,16);
        }else{
            clearTimeout(timer);
        }    
    },16);
}
</script>

 

【3】requestAnimationFrame

<div id="myDiv" style="background-color: lightblue;width: 0;height: 20px;line-height: 20px;">0%</div>
<button id="btn">run</button>
<script>
var timer;
btn.onclick = function(){
    myDiv.style.width = '0';
    cancelAnimationFrame(timer);
    timer = requestAnimationFrame(function fn(){
        if(parseInt(myDiv.style.width) < 500){
            myDiv.style.width = parseInt(myDiv.style.width) + 5 + 'px';
            myDiv.innerHTML =     parseInt(myDiv.style.width)/5 + '%';
            timer = requestAnimationFrame(fn);
        }else{
            cancelAnimationFrame(timer);
        }    
    });
}
</script>
相關文章
相關標籤/搜索