摘要:最近做微信小程序的開發(fā)時(shí),想做一個(gè)靠感知手機(jī)方向,使頁面上節(jié)點(diǎn)跟隨移動(dòng)的動(dòng)畫即重力感應(yīng)視差效果功能。最終實(shí)現(xiàn)的效果會(huì)有卡頓現(xiàn)象。如果是后臺(tái)標(biāo)簽頁面,重繪頻率則會(huì)大大降低。較于,能得到更完整的加速的支持。
最近做微信小程序的開發(fā)時(shí),想做一個(gè)靠感知手機(jī)方向,使頁面上節(jié)點(diǎn)跟隨移動(dòng)的動(dòng)畫(即重力感應(yīng)視差效果)功能。結(jié)果發(fā)現(xiàn)微信小程序有一些坑:
微信小程序不支持html5的DeviceOrientationEvent重力感應(yīng)API,而是自己實(shí)現(xiàn)的wx.onAccelerometerChange
這個(gè)API回調(diào)實(shí)現(xiàn),頻率為5次/s
在這個(gè)背景下,要實(shí)現(xiàn)平滑的重力感應(yīng)的視差體驗(yàn)就那么優(yōu)雅了,因?yàn)槿藢?duì)至少60幀每秒的動(dòng)畫才會(huì)感覺流暢。最終實(shí)現(xiàn)的效果會(huì)有卡頓現(xiàn)象。
實(shí)現(xiàn)期間,想起好像有requestAnimationFrame這個(gè)跟動(dòng)畫相關(guān)的API,其功能表現(xiàn)與setTimeout類似,即隔一段時(shí)間調(diào)用一個(gè)回調(diào)函數(shù)。對(duì)于這個(gè)API,之前了解不深,這次拿起來產(chǎn)生了一個(gè)疑問:既生setTimeout,何生requestAnimationFrame?帶著疑問,開始調(diào)研。
與setTimeout的不同在MDN上,關(guān)于requestAnimationFrame的定義是:
window.requestAnimationFrame()這個(gè)方法是用來在頁面重繪之前,通知瀏覽器調(diào)用一個(gè)指定的函數(shù),以滿足開發(fā)者操作動(dòng)畫的需求。這個(gè)方法接受一個(gè)函數(shù)為參,該函數(shù)會(huì)在重繪前調(diào)用。
在這里,我產(chǎn)生一個(gè)疑問,所謂的“在頁面重繪之前”,指的是,這個(gè)指定函數(shù)(以下簡(jiǎn)稱cb)會(huì)在底層機(jī)制的運(yùn)行下,在頁面重繪之前調(diào)用;還是人為地設(shè)置一個(gè)間隔時(shí)間,去調(diào)用cb,導(dǎo)致重繪?
之前大概了解過頁面的重排和重繪。動(dòng)畫能用重排和重繪來實(shí)現(xiàn)(這里指的是能用這兩種途徑來達(dá)到動(dòng)畫目的,而不是兩者都適合用來實(shí)現(xiàn)動(dòng)畫),而定義里只提到重繪,沒提到重排的原因,雖然我沒去細(xì)究,但很重要一點(diǎn)肯定是因?yàn)椋乩L性能遠(yuǎn)高于重排。所以動(dòng)畫不要通過left、margin等來實(shí)現(xiàn),應(yīng)該通過translate屬性來實(shí)現(xiàn)。
既然說到translate,稍微延伸一下,動(dòng)畫如果要用translate,最好用tranlate3d。因?yàn)?strong>較于tranlate,tranlate3d能得到更完整的GPU加速的支持,使得性能更優(yōu)。
言歸正傳,繼續(xù)解決剛剛的疑問。往下閱讀,發(fā)現(xiàn)這么一段解釋:
如果你想做逐幀動(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)簽頁面,重繪頻率則會(huì)大大降低。
從這段話可以看出,在用了這個(gè)方法后,瀏覽器會(huì)根據(jù)自己的重繪頻率,而每次重繪前會(huì)調(diào)用cb。用以下代碼驗(yàn)證:
var laststart function test () { laststart && console.log(Date.now() - laststart) laststart = Date.now() requestAnimationFrame(test) } requestAnimationFrame(test)
得到結(jié)果,我所在的瀏覽器環(huán)境(mac + chrome[55.0.2883.95])的重繪頻率約為60次每秒:
對(duì)此我產(chǎn)生幾個(gè)疑問:
問題1:如果我干擾了重繪的頻率,是否還會(huì)是一個(gè)幾乎保持在每秒60幀的頻率呢(只針對(duì)提高頻率進(jìn)行探究)?
問題2:是否調(diào)用了requestAnimationFrame就會(huì)產(chǎn)生一定頻率的重繪?
問題3:如果不調(diào)用requestAnimationFrame,在無其他代碼去重繪頁面的話,頁面就不會(huì)重繪嗎?
為了驗(yàn)證問題1,我加了這么一段代碼:
var x = 1 var style = document.querySelectorAll(".test")[0].style function interference () { x *= -1 style.transform = `translate3d(${x * 20}px, 0 ,0)` setTimeout(interference, 5) } interference()
得到的結(jié)果與上一個(gè)結(jié)果一致。
由此得出結(jié)論:cb的調(diào)用頻率在人為干擾重繪頻率的情況下,依舊我行我素。
等等,人為干擾重繪頻率成功了嗎?會(huì)不會(huì)雖然interference的調(diào)用頻率為5ms一次,但瀏覽器的重繪頻率依舊是約等于60次每秒,即interference雖然試圖去觸發(fā)瀏覽器5ms重繪一次,但瀏覽器只會(huì)阻塞住,等下一次瀏覽器默認(rèn)頻率重繪時(shí)再一起重繪?
為了探究這個(gè)問題,我將interference的setTimeout時(shí)間分別設(shè)置為16ms(簡(jiǎn)稱為i16)、10ms(簡(jiǎn)稱為i10)、8ms(簡(jiǎn)稱為i8)、5ms(簡(jiǎn)稱為i5),如果瀏覽器重繪頻率無法人為干擾,因以下兩個(gè)原因:
interference的函數(shù)對(duì)$(".test")的改變?yōu)樗轿灰普?fù)20px交替出現(xiàn)
瀏覽器默認(rèn)重繪頻率接近16ms一次
i8會(huì)因16ms中被調(diào)用2次,使得$(".test")回歸原位而導(dǎo)致肉眼看到的$(".test")閃動(dòng)頻率最慢;而i16的調(diào)用頻率和重繪頻率最為接近,在這種情況下,肉眼看到的$(".test")閃動(dòng)頻率會(huì)是最快。
結(jié)果肉眼看到的閃動(dòng)頻率從高到低依次是:i16 > i10、i5 > i8。
故得出結(jié)論,用上面的方法,無法人為干擾瀏覽器默認(rèn)的重繪頻率。
那么是否有辦法設(shè)置瀏覽器的重繪頻率呢?沒有查到直接答案,但在阮一峰的網(wǎng)頁性能管理詳解中,有提到:
大多數(shù)顯示器的刷新頻率是60Hz,為了與系統(tǒng)一致,以及節(jié)省電力,瀏覽器會(huì)自動(dòng)按照這個(gè)頻率,刷新動(dòng)畫
證明瀏覽器的重繪頻率和顯示器的刷新頻率相等。所以應(yīng)該沒有直接設(shè)置瀏覽器重繪頻率的方法,畢竟頁面重繪了,但顯示器沒刷新,影響了性能卻沒效果。
其實(shí)通過chrome自帶的開發(fā)者工具里的timeline功能,就能清晰看到,上面的方法的間隔時(shí)間無論怎么設(shè)置,都不會(huì)改變重繪頻率:
有了這個(gè)工具,其余兩個(gè)問題也迎刃而解:
問題2的答案:調(diào)用了requestAnimationFrame就會(huì)產(chǎn)生一定頻率的重繪,只是這種情況下的重繪會(huì)因并無實(shí)質(zhì)重繪內(nèi)容,而歷時(shí)極短。
問題3的答案:如果不調(diào)用requestAnimationFrame,在無其他代碼去重繪頁面的話,頁面就不會(huì)重繪
調(diào)研到這一步,發(fā)現(xiàn)requestAnimationFrame和setTimeout根本不是一回事。requestAnimationFrame是一個(gè)根據(jù)瀏覽器重繪頻率來調(diào)用的方法,setTimeout則是一個(gè)計(jì)時(shí)器。定義不同,適用的場(chǎng)景也完全不同,也沒有性能高低之分。
兼容性MDN給出的requestAnimationFrame的兼容性如下:
也就是說requestAnimationFrame肯定有兼容性問題。所以降級(jí)處理也是必須的。以下是降級(jí)代碼:
;(function() { var lastTime = 0; // 兼容各種瀏覽器 var vendors = ["ms", "moz", "webkit", "o"]; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+"RequestAnimationFrame"]; window.cancelAnimationFrame = window[vendors[x]+"CancelAnimationFrame"] || window[vendors[x]+"CancelRequestAnimationFrame"]; } // 降級(jí)處理 if (!window.requestAnimationFrame) { window.requestAnimationFrame = function(callback, element) { // 保證如果重復(fù)執(zhí)行callback的話,callback的執(zhí)行起始時(shí)間相隔16ms var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (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); }; } }());requestAnimationFrame在微信小程序里的表現(xiàn)
微信iOS版小程序完全不支持requestAnimationFrame
結(jié)論requestAnimationFrame和setTimeout根本不是一回事,根據(jù)其定義,可以在不同場(chǎng)景下使用。
較于tranlate,tranlate3d能得到更完整的GPU加速的支持。
瀏覽器對(duì)頁面的重繪有一個(gè)默認(rèn)的最大頻率,最大頻率無法人為設(shè)置,也沒有設(shè)置的必要。
調(diào)用了requestAnimationFrame就會(huì)產(chǎn)生一定頻率的重繪,只是這種情況下的重繪會(huì)因并無實(shí)質(zhì)重繪內(nèi)容,而歷時(shí)極短。
如果不調(diào)用requestAnimationFrame,在無其他代碼去重繪頁面的話,頁面就不會(huì)重繪。
最后,附上我們?nèi)さ昙瘓F(tuán)的小程序二維碼:
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/91670.html
摘要:最近做微信小程序的開發(fā)時(shí),想做一個(gè)靠感知手機(jī)方向,使頁面上節(jié)點(diǎn)跟隨移動(dòng)的動(dòng)畫即重力感應(yīng)視差效果功能。最終實(shí)現(xiàn)的效果會(huì)有卡頓現(xiàn)象。如果是后臺(tái)標(biāo)簽頁面,重繪頻率則會(huì)大大降低。較于,能得到更完整的加速的支持。 最近做微信小程序的開發(fā)時(shí),想做一個(gè)靠感知手機(jī)方向,使頁面上節(jié)點(diǎn)跟隨移動(dòng)的動(dòng)畫(即重力感應(yīng)視差效果)功能。結(jié)果發(fā)現(xiàn)微信小程序有一些坑: 微信小程序不支持html5的DeviceOrie...
摘要:最近做微信小程序的開發(fā)時(shí),想做一個(gè)靠感知手機(jī)方向,使頁面上節(jié)點(diǎn)跟隨移動(dòng)的動(dòng)畫即重力感應(yīng)視差效果功能。最終實(shí)現(xiàn)的效果會(huì)有卡頓現(xiàn)象。如果是后臺(tái)標(biāo)簽頁面,重繪頻率則會(huì)大大降低。較于,能得到更完整的加速的支持。 最近做微信小程序的開發(fā)時(shí),想做一個(gè)靠感知手機(jī)方向,使頁面上節(jié)點(diǎn)跟隨移動(dòng)的動(dòng)畫(即重力感應(yīng)視差效果)功能。結(jié)果發(fā)現(xiàn)微信小程序有一些坑: 微信小程序不支持html5的DeviceOrie...
摘要:月份前端資源分享更多資源請(qǐng)文章轉(zhuǎn)自前端生成好看的二維碼十大經(jīng)典排序算法帶動(dòng)圖演示為什么知乎前端圈普遍認(rèn)為游戲和展示的個(gè)人整理和封裝的庫中文詳細(xì)注釋供新手學(xué)習(xí)使用擴(kuò)展語法記錄掉坑初期工具漢字拼音轉(zhuǎn)換工具實(shí)現(xiàn)漢字轉(zhuǎn)拼音的插件下拉列表支持拼音簡(jiǎn) 2月份前端資源分享 更多資源請(qǐng)Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github...
平日學(xué)習(xí)接觸過的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個(gè)網(wǎng)址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二維碼 十大經(jīng)典排序算法(帶動(dòng)圖演示) 為什么知乎前端圈普遍認(rèn)為H5游戲和H5展示的JSer 個(gè)人整理和封裝的YU.js庫|中文詳細(xì)注釋|供新手學(xué)習(xí)使用 擴(kuò)展JavaScript語法記錄 - 掉坑初期工具 漢字拼音轉(zhuǎn)換...
平日學(xué)習(xí)接觸過的網(wǎng)站積累,以每月的形式發(fā)布。2017年以前看這個(gè)網(wǎng)址:http://www.kancloud.cn/jsfron... 1. Javascript 前端生成好看的二維碼 十大經(jīng)典排序算法(帶動(dòng)圖演示) 為什么知乎前端圈普遍認(rèn)為H5游戲和H5展示的JSer 個(gè)人整理和封裝的YU.js庫|中文詳細(xì)注釋|供新手學(xué)習(xí)使用 擴(kuò)展JavaScript語法記錄 - 掉坑初期工具 漢字拼音轉(zhuǎn)換...
閱讀 2652·2021-09-09 09:33
閱讀 2810·2019-08-30 15:54
閱讀 2867·2019-08-30 14:21
閱讀 2356·2019-08-29 17:15
閱讀 3580·2019-08-29 16:13
閱讀 2759·2019-08-29 14:21
閱讀 3422·2019-08-26 13:25
閱讀 2028·2019-08-26 12:14