在JS開發(fā)中經常會用到定時器,尤其是一些動畫特效,小游戲等完全依靠定時器驅動。
要讓動畫跑得更流暢,我們常常使用較高的刷新率,例如60fps。由于每一幀的間隔非常短,很難看清楚每一幀具體的運行情況。
有時整體上看似乎一切良好,但如果放慢定時器的速度,卻會發(fā)現(xiàn)其中有部分幀或因代碼里的小問題,并沒有按我們想象那樣顯示。由于播放的非?,這些潛在的小問題都掩蓋了。
為了方便動畫腳本的觀察和調試,我們嘗試用js模仿一個類似windows下經典的應用程序:變速齒輪,能即時修改系統(tǒng)時鐘的運行頻率!這聽起來似乎很神奇吧~其實原理并不復雜。
和傳統(tǒng)的變速齒輪運行機制一樣,我們使用鉤子程序勾住默認那幾個定時器相關的API —— setTimeout, setInterval, clearTimeout, clearInterval。當然,所謂的鉤子程序,無非就是預先保存原來的API引用,接著用自己的程序覆蓋他們。這樣我們就可以攔截之后的定時器調用,然后根據虛擬時鐘的速率,自己維護回調隊列,于是就產生了定時器變速的效果。如果同步上再嚴密點,甚至還可以覆蓋Date對象,讓時間的流逝速度都隨之而變!
當然,有不少問題仍然難以解決的。
時鐘頻率被加快后,每一幀的時間間隔被大幅縮短,甚至小于1ms。而js定時器頻率眾所周知,遠達不到這樣的精度。于是只能用“跳幀”來解決這個問題。例如,一個2ms的定時器,理論上應該每2ms觸發(fā)一次,但某個瀏覽器最短只支持16ms的間隔,那么每次定時器觸發(fā)內循環(huán)調用 16/2 = 8次回調,來彌補頻率上的不足。但由于這8次回調是在同個事件里一口氣執(zhí)行的,所以前7次的界面操作都不會立即渲染出來,只有第8次的操作才會有所表現(xiàn),所以就有了“跳”的感覺。
但是這個方法只能解決 setInterval 的定時器,因為它的時間間隔以及回調都是固定的。對于 setTimeout 這樣每次延時不確定的,甚至還無法確定下一幀是否接著運行,跳幀機制就有些無從為力了。
不過只實現(xiàn)一個基本功能的還是比較容易的:
JsGear,就是根據這個思路實現(xiàn)的 JavaScript 變速齒輪插件,對時間相關的API都進行了嚴密的封裝。因為它完全是用js/css制作的,所以不依賴任何插件,引入頁面就可以使用。
為了讓使用更快捷,這兩天換了一個新概念的操作界面,并且支持IE6+, FireFox, Chrome, Safari, Opera瀏覽器,以及Quirks模式。
測試Demo: http://www.etherdream.com/JSGear/demo.html
在自己的頁面里測試很簡單,把jsgear.js插入到所有的腳本之前就可以。這里上傳了一份到博客附件里,復制下面代碼到自己的頁面內即可使用:
<scrpt src="http://files.cnblogs.com/jsapp/jsgear.js"></script>
當然,目前還只是演示版本,實現(xiàn)了基本功能,還有不少小問題。大家要是有什么好多思路和建議,歡迎探討。