時間分片
早在react16發佈以前,就有個新鮮玩意兒被炒的沸沸揚揚,對,就是時間分片這個東西。可是這個挺起來高大上的玩意兒究竟是個啥呢?接下來咱們就分析一下~
在分析時間分片以前,咱們要先拋出三個問題:
1. 爲何須要時間分片?
2. 時間分片是怎麼實現的?
3. 所謂的時間分片它"分"的究竟是啥?
接下來咱們就能夠帶着以上這三個問題一塊兒去研究研究時間分片這個妮子了~
css
1. 爲何須要時間分片?
答: 由於牛逼!
其實每一個新功能的誕生,都必定是爲了解決某種可能會存在問題的應用場景的,不然就是個憨逼。因此時間分片也必然是爲了處理react15中所存在的某種問題的。你們能夠本身試驗一下,使用react15去渲染1個動畫 + 1萬個節點,而後去更新這10萬個節點,看看你的瀏覽器能不能頂得住,我這裏準備了個demo,你們能夠放進瀏覽器跑一跑~react15 demo
你們能夠發現,一旦當節點多了的時候,程序會變的比較卡頓,這樣是react15以前一直被人病詬的緣由。因而這個時候,time split閃亮登場!
那麼問題來了,當頁面中節點多了,使用時間分片就能夠阻止卡頓嗎?
答案其實否認的。使用時間分片並不能阻止頁面產生卡頓,與其說是阻止卡頓,更確切地說法實際上是: 「減輕程序中,優先級較高的事物(好比css動畫)的卡頓時間」。這句話可能目前不太好理解,等我們往下分析,一會就明瞭了,你們就先記住,時間分片的做用簡單來說就是上面這句話~
html
2. 時間分片是怎麼實現的?
在說時間分片以前,咱們須要來了解一下瀏覽器中的「幀」的概念。
首先「幀」是什麼呢?咱們在瀏覽網頁滑動滑輪頁面會往下出溜對吧,或者css3出來以後常常能在網站中看到一些很炫酷的動畫哈,其實咱們所看到的頁面,從始至終都是靜態的,可是之因此能看到頁面很流暢的往下滑或者感到動畫運行的很流暢的根本緣由,實際上是瀏覽器在不停地刷新頁面,瀏覽器經過很高的頻率去刷新頁面讓頁面不停地變化,這才使咱們能感到頁面的運行是流暢的。經驗代表,當1秒鐘頁面刷新33次左右可以使咱們看到比較流暢的動畫,也就是須要每隔 大約(1000ms / 33)33ms刷新一次頁面。因此有時咱們使用setInterval寫動畫,第二個參數若是大於33ms可能會感受到不太流暢。很早之前你們據說過的flash動畫,若是我沒記錯好像是一秒20幀吧,因此flash的體驗並非特別好,如今也就被逐漸淘汰了。
咱們如今知道了瀏覽器會不停地刷新頁面(谷歌控制檯裏能夠喚出顯示刷新頻率的小窗口),而且通常狀況下每隔33ms刷新一下能夠保證流暢(並不絕對是33ms,像谷歌有時候多是16ms刷新一次,vr好像是1秒刷新90次,3d好像是120次,咱們在這篇文章的後面都假設瀏覽器的刷新頻率是 33ms),在這33ms內的頁面實際上是靜態不動的。
那每一幀當中瀏覽器都幹了什麼事情呢?咱們來看下面一張圖:react
簡單總結一下上面的圖,其實瀏覽器的每一幀均可以概括爲四個部分:
執行js + 執行requestAnimation + 瀏覽器計算dom位置並從新刷新頁面 + 第四部分
上圖中對於這「這第四部分」並無表示出來。其實還有另一張圖:
上圖中黃色的部分其實就是所謂的「第四部分」。你們能夠看到,這個部分執行了一個叫作idleCallback的東西,這是個啥呢?其實它也是瀏覽器原生提供的一個函數,它的全名叫作requestIdleCallback,和requestAnimationFrame很相似,是一個跟「幀」相關的回調函數。從第一張圖能夠看出requestAnimationFrame是執行在頁面從新渲染以前的,而從第二張圖片能發現,這個requestIdleCallback是執行在frame commit以後,在整個幀的最後,當咱們的業務代碼的js,requestAnimationFrame,以及頁面都從新渲染完了後,它纔會執行。Idle的中文其實就是「閒散」的意思。換句話說,
requestIdleCallback執行在每一幀(假設33ms)剩餘的空閒時間中。
啥意思呢,舉個🌰,假設咱們的業務中的同步js代碼執行了10ms,而後requestAnimationFrame中又修改了某個dom的位置,這部分的代碼又執行了5ms,以後進入到layout步驟,瀏覽器底層開始從新計算dom們的位置,計算完了從新刷新了一邊頁面花費了5ms,最終:
10ms + 5ms + 5ms = 20ms
而向咱們剛剛所說的,每一幀是33ms,那麼 33ms - 20ms = 13ms,這剩下的13ms幹啥呢?沒錯!就幹requestIdleCallback這個函數!這個函數中的全部代碼都會放到這一幀所剩下的時間中去執行!
咱們能夠想想,把代碼放在這一幀剩餘的時間中有什麼好處呢?
咱們剛剛已經說過了,這個函數是執行在頁面從新渲染以後,也就是說,
這個時間段執行的任何代碼,不會影響到咱們視覺上的感知!
再舉個🌰:
1. 我有個div,每次往右移動 1px,我想讓他最終到達3px的位置
2. 在requestAnimationFrame中每次讓該div的 left 加 1px
3. 第一幀的時候在 33ms 以內,第一步執行了js代碼,第二步執行了requestAnimation,第三步刷新了頁面,此時的 該div位置是 1px
4. 第二幀的時候在 33ms 以內,第一步執行了js代碼,第二步執行了requestAnimation,第三步刷新了頁面,此時的 該div位置是 2px
5. 第三幀的時候在 33ms 以內,第一步執行了js代碼,第二步執行了requestAnimation,第三步刷新了頁面,此時的 該div位置是 3px,達到了目的地
6. 你們要注意的是,因爲每次從新渲染頁面,都發生在33ms以內,因此對於咱們的肉眼來說,第2步到第4步的div位移過程是一個連續運動的過程!
7. 因此,若是這三幀,每一幀在刷新完頁面以後還剩餘一些時間的話,咱們在這部分時間中執行的代碼,是徹底不影響咱們視覺上的流暢的!
這個時候你們也許就能想到一個很牛逼的事情: 「
若是咱們把項目中的全部複雜的計算過程都放到這種一幀中剩餘的時間中,那不就徹底不影響其餘動畫或者交互了嘛!」
沒錯!理論上講確實是這樣的!react16中,也正是應用這種方法,來作到儘可能減小對動畫等優先級較高的操做的卡頓的。那麼react16中是怎麼作的呢?
react16中,若是開啓了異步渲染模式(時間分片模式)的話,就會把全部的複雜的操做放到每一幀的空閒時間中,從而達到不影響優先級較高的操做的目的。複雜的操做好比「diff算法」,「初始化函數或class組件」,「執行組件生命週期」,「建立或更新fiber樹」等都算是複雜的操做。經過將這種複雜的同步算法,放到了不影響視覺流暢的空閒時間當中,這就是react16中的時間分片的假面!
到此爲止我們討論了最開始提出的前倆個問題:爲何要時間分片以及時間分片實現原理,可是爲啥說是時間分片的「假面」呢?還有我們開始提出的第三個問題:時間分片分的究竟是啥呢,咱們下一回再討論~
下一篇: 時間分片分的究竟是啥?
css3