摘要:組件的性能優化高德納我們應該忘記忽略很小的性能優化,可以說的情況下,過早的優化是萬惡之源,而我們應該關心對性能影響最關鍵的另外的代碼。對多個組件的性能優化當一個組件被裝載更新和卸載時,組件的一序列生命周期函數會被調用。
React組件的性能優化
高德納: "我們應該忘記忽略很小的性能優化,可以說97%的情況下,過早的優化是萬惡之源,
而我們應該關心對性能影響最關鍵的另外3%的代碼。"
不要將性能優化的精力浪費在對整體性能提高不大的代碼上,而對性能有關鍵影響的部分,
優化并不嫌早。因為,對性能影響最關鍵的部分,往往涉及解決方案核心,決定整體的架構,
將來要改變的時候牽扯更大。
React利用Virtual DOM來提升渲染性能,雖然每一次頁面更新都是最組件的從新渲染,
但是并不是將之前的渲染內容全部拋棄重來,借助Virtual DOM,React能夠計算出對DOM
樹的最少修改,這就是React默認情況下渲染都很迅速的秘訣;
不過,雖然Virtual DOM能夠將每次DOM操作量減少到最小,但,計算和比較Virtual DOM依然是一個復雜的過程;
當然,如果能夠在開始計算Virtual DOM之前就判斷渲染的結果不會有變化,那么就可以不進行Virtual DOM計算和比較,速度就會更快。
2.shouldComponentUpdate的默認實現方式既然可以對組件在開始計算Virtual DOM之前判斷渲染結果不會有變化時,阻止渲染的進行,
從而提升性能,那么我們自然想到使用shouldComponentUpdate(nextProp,nextState)
shouldComponentUpdate函數在render函數之前調用,決定“什么時候不需要從新渲染”;
即返回一個布爾值,決定更新是否進行下去,默認返回true,若返回false則中斷更新;
shouldComponentUpdate(nextProp,nextState){ return (nextProp.completed !== this.props.completed) || (nextProp.text !== this.props.text) }
其中nextProps為此次更新傳入的props,對于這個組件,影響渲染內容的prop只有completed和text,
只要確保這兩個prop沒有變化,shouldComponentUpdate就可以返回false阻止沒必要的更新
但是,上述的比較只是‘淺層比較’,如果類型是基本類型,只要值相同,那么“淺層比較”
也會認為二者相同:
那,如果prop的類型是復雜的對象怎么辦?
對于復雜對象,‘淺層比較’的方式只看這兩個prop是不是同一個對象的引用,如果不是,哪怕
對象中的內容完全一樣也會認為是不同的兩個prop。
那么使用“深層比較”:但對對象的結構是無法預知的,如果遞歸對每個字段都進行“深層比較”,
不光會讓代碼更加復雜,也可能會造成性能問題。
所以,要想判斷前后的對象類型的prop是相同的,就必須要保證prop是指向同一個JavaScript對象:
要避免使用上面的傳入方式,應為每次渲染都會重新創建{color: "red"}對象,引用地址每次都不同,將導致每次的styleProp都不同。
const footStyle = {color: "red"};//確保這個初始化只執行一次,不要放在render函數中
使用‘單例模式’確保傳入的styleProp指向同一個對象
如果是函數呢?
onToggleTodo(item.id)}/>
應該避免使用上面的函數傳遞模式,因為這里賦值的是一個匿名函數,而且是在賦值的時候產生的,也就是說
每次渲染都會產生一個新的函數,這就是問題所在。
如果要傳遞的prop很多呢?
恩~~用React-Redux的話,有對shouldComponentUpdate的默認實現。
3. 對多個React組件的性能優化當一個React組件被裝載、更新和卸載時,組件的一序列生命周期函數會被調用。不過,這些生命周期函數是針對一個
特定的React組件函數,在一個應用中,從上而下有很多React組件組合起來,它們之間的渲染過程要更加復雜。
同樣一個組件的渲染過程也要考慮三個過程:裝載階段、更新階段、卸載階段
對于裝載階段,組件無論如何都要徹底渲染一次,從這個React組件往下的所有子組件,都要經歷一遍React組件的裝載生命
周期,所以并沒有多少優化的事情可做。
對于卸載階段,只有一個生命周期函數componentWillUnmount,這個函數只是清理componentDidMount添加的事件處理監聽等收尾工作,
所以,也沒有什么可優化的空間;
在組件更新過程,會構建更新Virtual DOM,并將其與之前的Virtual DOM進行比較,從而找出不同之處,使用最少的DOM操作進行更新
調和過程:即React更新中對Virtual DOM找不同的過程,通常對比兩個N個節點的樹形結構的算法,時間復雜度是O(n*3),如果直接
使用默認對比,節點過多的話,需要操作的數量太多,而React不可能采用這種算法;
React實際采用的算法時間復雜度是O(N)(時間復雜度只是對一個算法最好和最差情況下需要的指令操作數量級的估量)
React的Reconciliation算法并不復雜,首先檢查兩個樹形的根節點的類型是否相同,根據相同或者不同有不同的處理方式:
節點類型不同的情況
如果樹形節點的類型不相同,那就意味著改動很大,直接認為原來的那個樹形結構已經沒用,可以扔掉,需要從新構建DOM樹,
原有的樹形上的React組件便會經歷“卸載”的生命周期;
也就是說,對于Virtual DOM樹這是一個“更新”過程,但是卻可能引發這個樹結構上某些組件的“裝載”和“卸載”過程
如:
更新前
我們想要更新成這樣:
>1. 那么在作比較的時候,一看根節點原來是div,新的是span,類型就不一樣了,那么這個算法就廢棄之前的div包括里面的所有子節點, 從新構建一個span節點和子節點; >2. 很明顯因為根節點不同就將所有的子節點從新構建,這很浪費,但是為了避免O(N*3)的時間復雜度,React這能選擇這種比較簡單、快捷的方法; >3. 所以,作為開發者,我們一定要避免上面的浪費的情景出現
節點類型相同的情況
如果兩個節點類型相同時,對于DOM元素,React會保留節點對應的DOM元素,只對其節點的屬性和內容做對比,然后只修改更新的部分;
節點類型相同時,對于React組件類型,React做得是根據新節點的props去更新節點的組件實例,引發組件的更新過程;
在處理完根節點對比后,React的算法會對根節點的每一個子節點重復一樣的操作
多個相同子組件的情況
如果最初組件狀態為:
更新后為:
那么React會創建一個新的TodoItem組件實例,而前兩個則進行正常的更新過程但是,如果更新后為:
(這將暴露一個問題)理想處理方式是,創建一個新的TodoItem組件實例放在第一位,后兩個進入自然更新過程
但是要讓react按照這種方式,就必須找兩個子組件的不同之處,而現有計算兩個序列差異的算法時間是O(N*2),顯然則
不適合對性能要求很高的場景,所以React選擇了一個看起來很傻的辦法,即挨個比較每個子組件;
React首先認為把text為First的組件的text改為Zero,Second的改為First,最后創建一個text為Second的組件,這樣便會破原有的兩個組件完成一個更新過程,并創建一個text為Second的新組件
這顯然是一個浪費,React也意到,并提供了方克服,不過需要開發人員提供一點幫助,這就是key
Key的使用
key屬性可以明確的告訴React每個組件的唯一標識
如果最初組件狀態為:
更新后為:
因為有唯一標識key,React可以根據key值,知道現在的第二和第三個組件就是之前的第一和第二個,便用原來的props啟動更新過程,
這樣shouldComponentUpdate就會發生作用,避免無謂的更新;
注意:因為作為組件的唯一標識,所以key必須唯一,且不可變
下面的代碼是錯誤的例子:
使用數組下標作為key值,看起來唯一,但不穩定,因為隨著todos數組值的不同,同樣一個組件實例在不同的更新過程中數組的下標完全可能不同,
把下標當做可以就會讓React亂套,記住key不僅要唯一還要確保穩定不可變
需要注意:雖然key是一個prop,但是接受key的組件不能讀取key的值,因為key和ref是React保留的兩個特殊prop,并沒有預期讓組將直接訪問。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93088.html
摘要:工程實踐立足實踐,提示實際水平內聯函數與性能很多關于性能優化的文章都會談及內聯函數,其也是常見的被詬病為拖慢性能表現的元兇之一不過本文卻是打破砂鍋問到底,論證了內聯函數并不一定就會拖慢性能,過度的性能優化反而會有損于應用性能。 showImg(https://segmentfault.com/img/remote/1460000011481413?w=1240&h=825); 前端每周...
摘要:感謝王下邀月熊分享的前端每周清單,為方便大家閱讀,特整理一份索引。王下邀月熊大大也于年月日整理了自己的前端每周清單系列,并以年月為單位進行分類,具體內容看這里前端每周清單年度總結與盤點。 感謝 王下邀月熊_Chevalier 分享的前端每周清單,為方便大家閱讀,特整理一份索引。 王下邀月熊大大也于 2018 年 3 月 31 日整理了自己的前端每周清單系列,并以年/月為單位進行分類,具...
摘要:前端每周清單第期現狀分析與優化策略單元測試爬蟲作者王下邀月熊編輯徐川前端每周清單專注前端領域內容,以對外文資料的搜集為主,幫助開發者了解一周前端熱點分為新聞熱點開發教程工程實踐深度閱讀開源項目巔峰人生等欄目。 showImg(https://segmentfault.com/img/remote/1460000011008022); 前端每周清單第 29 期:Web 現狀分析與優化策略...
摘要:發布是由團隊開源的,操作接口庫,已成為事實上的瀏覽器操作標準。本周正式發布,為我們帶來了,,支持自定義頭部與腳部,支持增強,兼容原生協議等特性變化。新特性介紹日前發布了大版本更新,引入了一系列的新特性與提升,本文即是對這些變化進行深入解讀。 showImg(https://segmentfault.com/img/remote/1460000012940044); 前端每周清單專注前端...
閱讀 3161·2021-11-04 16:09
閱讀 3124·2021-09-23 11:49
閱讀 3645·2021-09-09 09:33
閱讀 3626·2021-08-18 10:22
閱讀 2046·2019-08-30 15:55
閱讀 3633·2019-08-30 15:53
閱讀 2661·2019-08-28 18:08
閱讀 895·2019-08-26 18:18