如果您一直在使用 requestAnimationFrame
,您會發現您的繪圖會與螢幕的更新率同步,因此可產生最精確的動畫。此外,當使用者切換至其他分頁時,您也能減少 CPU 風扇噪音和電池耗電量。
不過,部分 API 即將變更。傳遞至回呼函式的時間戳記會從一般 Date.now()
類型的時間戳記變更為高解析度測量值,以浮點數毫秒表示自網頁開啟以來的時間。如果您使用這個值,就必須根據下方說明更新程式碼。
為了清楚說明,以下是我的意思:
// assuming requestAnimationFrame method has been normalized for all vendor prefixes..
requestAnimationFrame(function(timestamp){
// the value of timestamp is changing
});
如果您使用的是這裡提供的常見 requestAnimFrame
墊片,就不會使用時間戳記值。你已退出候補名單。:)
原因
這是因為好的 rAF 能協助你取得理想中的每秒 60 fps,而 60 fps 則須達到每影格 16.7 毫秒。不過,如果以整數毫秒為單位進行測量,表示我們觀察和指定的所有項目都會以 1/16 為精確度。
如上圖所示,藍色長條代表在繪製新影格 (以 60fps 為例) 前,您有多少時間可執行所有工作。您可能會執行超過 16 項作業,但如果使用整數毫秒,您只能以這些非常粗略的增量來排程及測量。這還不夠。
高解析度計時器可提供更精確的數據,解決這個問題:
Date.now() // 1337376068250
performance.now() // 20303.427000007
高解析度計時器目前在 Chrome 中可用 window.performance.webkitNow()
,這通常等於傳遞至 rAF 回呼的新引數值。讓規格進一步通過標準後,該方法就會捨棄前置字元,並透過 performance.now()
取得。
您也會發現,上述兩個值的數量級相差甚遠。performance.now()
是自特定網頁開始載入 (具體來說是 performance.navigationStart
) 以來的浮點毫秒測量值。
使用中
裁剪的主要問題是使用此設計模式的動畫程式庫:
function MyAnimation(duration) {
this.startTime = Date.now();
this.duration = duration;
requestAnimFrame(this.tick.bind(this));
}
MyAnimation.prototype.tick = function(time) {
var now = Date.now();
if (time > now) {
this.dispatchEvent("ended");
return;
}
...
requestAnimFrame(this.tick.bind(this));
}
修正這個問題的編輯方式相當簡單... 擴充 startTime
和 now
即可使用 window.performance.now()
。
this.startTime = window.performance.now ?
(performance.now() + performance.timing.navigationStart) :
Date.now();
這是相當簡單的實作方式,不會使用前置字串 now()
方法,且會假設 Date.now()
支援,但 IE8 並未支援 Date.now()
。
特徵偵測
如果您未使用上述模式,只想找出收到的回呼值類型,可以使用以下技巧:
requestAnimationFrame(function(timestamp){
if (timestamp < 1e12){
// .. high resolution timer
} else {
// integer milliseconds since unix epoch
}
// ...
檢查 if (timestamp < 1e12)
是快速測試,可用來判斷我們要處理的數字有多大。從技術層面來說,如果網頁持續開啟 30 年,就有可能出現誤判。但我們無法測試它是否為浮點數 (而非四捨五入為整數)。請要求足夠的高解析度計時器,這樣您就一定會在某個時間點取得整數值。
我們預計在 Chrome 21 中推出這項異動,因此如果您已開始使用這個回呼參數,請務必更新程式碼!