摘要:當大家考慮在項目中使用的時候,第一個問題往往是他們的應用的速度和響應是否能和非版一樣,每當狀態改變的時候就重新渲染組件的整個子樹,讓大家懷疑這會不會對性能造成負面影響。
當大家考慮在項目中使用 React 的時候,第一個問題往往是他們的應用的速度和響應是否能和非 React 版一樣,每當狀態改變的時候就重新渲染組件的整個子樹,讓大家懷疑這會不會對性能造成負面影響。React 用了一些黑科技來減少 UI 更新需要的花費較大的 DOM 操作。
使用 production 版本如果你在你的 React app 中進行性能測試或在尋找性能問題,一定要確定你在使用 minified production build。開發者版本包括額外的警告信息,這對你在開發你的 app 的時候很有用,但是因為要進行額外的處理,所以它也會比較慢。
避免更新 DOMReact 使用虛擬 DOM,它是在瀏覽器中的 DOM 子樹的渲染描述,這個平行的描述讓 React 避免創建和操作 DOM 節點,這些遠比操作一個 JavaScript 對象慢。當一個組件的 props 或 state 改變,React 會構造一個新的虛擬 DOM 和舊的進行對比來決定真實 DOM 更新的必要性,只有在它們不相等的時候,React 才會使用盡量少的改動更新 DOM。
在此之上,React 提供了生命周期函數 shouldComponentUpdate,在重新渲染機制回路(虛擬 DOM 對比和 DOM 更新)之前會被觸發,賦予開發者跳過這個過程的能力。這個函數默認返回 true,讓 React 執行更新。
shouldComponentUpdate: function(nextProps, nextState) { return true; }
一定要記住,React 會非常頻繁的調用這個函數,所以要確保它的執行速度夠快。
假如你有個帶有多個對話的消息應用,如果只有一個對話發生改變,如果我們在 ChatThread 組件執行 shouldComponentUpdate,React 可以跳過其他對話的重新渲染步驟。
shouldComponentUpdate: function(nextProps, nextState) { // TODO: return whether or not current chat thread is // different to former one. }
因此,總的說,React 通過讓用戶使用 shouldComponentUpdate 減短重新渲染回路,避免進行昂貴的更新 DOM 子樹的操作,而且這些必要的更新,需要對比虛擬 DOM。
shouldComponentUpdate 實戰這里有個組件的子樹,每一個都指明了 shouldComponentUpdate 返回值和虛擬 DOM 是否相等,最后,圓圈的顏色表示組件是否需要更新。
在上面的示例中,因為 C2 的 shouldComponentUpdate 返回 false,React 就不需要生成新的虛擬 DOM,也就不需要更新 DOM,注意 React 甚至不需要調用 C4 和 C5 的 shouldComponentUpdate。
C1 和 C3 的 shouldComponentUpdate 返回 true,所以 React 需要向下到葉子節點檢查它們,C6 返回 true,因為虛擬 DOM 不相等,需要更新 DOM。最后感興趣的是 C8,對于這個節點,React 需要計算虛擬 DOM,但是因為它和舊的相等,所以不需要更新 DOM。
注意 React 只需要對 C6 進行 DOM 轉換,這是必須的。對于 C8,通過虛擬 DOM 的對比確定它是不需要的,C2 的子樹和 C7,它們甚至不需要計算虛擬 DOM,因為 shouldComponentUpdate。
那么,我們怎么實現 shouldComponentUpdate 呢?比如說你有一個組件僅僅渲染一個字符串:
React.createClass({ propTypes: { value: React.PropTypes.string.isRequired }, render: function() { return{this.props.value}; } });
我們可以簡單的實現 shouldComponentUpdate 如下:
shouldComponentUpdate: function(nextProps, nextState) { return this.props.value !== nextProps.value; }
非常好!處理這樣簡單結構的 props/state 很簡單,我門甚至可以歸納出一個基于淺對比的實現,然后把它 Mixin 到組件中。實際上 React 已經提供了這樣的實現: PureRenderMixin
但是如果你的組件的 props 或者 state 是可變的數據結構呢?比如說,組件接收的 prop 不是一個像 "bar" 這樣的字符串,而是一個包涵字符串的 JavaScript 對象,比如 { foo: "bar" }:
React.createClass({ propTypes: { value: React.PropTypes.object.isRequired }, render: function() { return{this.props.value.foo}; } });
前面的 shouldComponentUpdate 實現就不會一直和我們期望的一樣工作:
// assume this.props.value is { foo: "bar" } // assume nextProps.value is { foo: "bar" }, // but this reference is different to this.props.value this.props.value !== nextProps.value; // true
這個問題是當 prop 沒有改變的時候 shouldComponentUpdate 也會返回 true。為了解決這個問題,我們有了這個替代實現:
shouldComponentUpdate: function(nextProps, nextState) { return this.props.value.foo !== nextProps.value.foo; }
基本上,我們結束了使用深度對比來確保改變的正確跟蹤,這個方法在性能上的花費是很大的,因為我們需要為每個 model 寫不同的深度對比代碼。就算這樣,如果我們沒有處理好對象引用,它甚至不能工作,比如說這個父組件:
React.createClass({ getInitialState: function() { return { value: { foo: "bar" } }; }, onClick: function() { var value = this.state.value; value.foo += "bar"; // ANTI-PATTERN! this.setState({ value: value }); }, render: function() { return ( ); } });
內部組件第一次渲染的時候,它會獲取 { foo: "bar" } 作為 value 的值。如果用戶點擊了 a 標簽,父組件的 state 會更新成 { value: { foo: "barbar" } },觸發內部組件的重新渲染過程,內部組件會收到 { foo: "barbar" } 作為 value 的新的值。
這里的問題是因為父組件和內部組件共享同一個對象的引用,當對象在 onClick 函數的第二行發生改變的時候,內部組件的屬性也發生了改變,所以當重新渲染過程開始,shouldComponentUpdate 被調用的時候,this.props.value.foo 和 nextProps.value.foo 是相等的,因為實際上 this.props.value 和 nextProps.value 是同一個對象的引用。
因此,我們會丟失 prop 的改變,縮短重新渲染過程,UI 也不會從 "bar" 更新到 "barbar"
Immutable-js 來救贖Immutable-js 是 Lee Byron 寫的 JavaScript 集合類型的庫,最近被 Facebook 開源,它通過結構共享提供不可變持久化集合類型。一起看下這些特性的含義:
Immutable: 一旦創建,集合就不能再改變。
Persistent: 新的集合類型可以通過之前的集合創建,比如 set 產生改變的集合。創建新的集合之后源集合仍然有效。
Structural Sharing: 新的集合會使用盡量多的源集合的結構,減少復制來節省空間和性能友好。如果新的集合和源集合相等,一般會返回源結構。
不可變讓跟蹤改變非常簡單;每次改變都是產生新的對象,所以我們僅需要對象的引用是否改變,比如這段簡單的 JavaScript 代碼:
var x = { foo: "bar" }; var y = x; y.foo = "baz"; x === y; // true
盡管 y 被改變,因為它和 x 引用的是同一個對象,這個對比返回 true。然而,這個代碼可以使用 immutable-js 改寫如下:
var SomeRecord = Immutable.Record({ foo: null }); var x = new SomeRecord({ foo: "bar" }); var y = x.set("foo", "baz"); x === y; // false
這個例子中,因為改變 x 的時候返回了新的引用,我們就可以安全的認為 x 已經改變。
臟檢測可以作為另外的可行的方式追蹤改變,給 setters 一個標示。這個方法的問題是,它強制你使用 setters,而且要寫很多額外的代碼,影響你的類?;蛘吣憧梢栽诟淖冎吧羁截悓ο?,然后進行深對比來確定是不是發生了改變。這個方法的問題是,深拷貝和深對比都是很花性能的操作。
因此,不可變數據結構給你提供了一個高效、簡潔的方式來跟蹤對象的改變,而跟蹤改變是實現 shouldComponentUpdate 的關鍵。所以,如果我們使用 immutable-js 提供的抽象創建 props 和 state 模型,我們就可以使用 PureRenderMixin,而且能夠獲得很好的性能增強。
Immutable-js 和 Flux如果你在使用 Flux,你應該開始使用 immutable-js 寫你的 stores,看一下 full API。
讓我們看一個可行的方式,使用不可變數據結構來給消息示例創建數據結構。首先我們要給每個要建模的實體定義一個 Record。Records 僅僅是一個不可變容器,里面保存一系列具體數據:
var User = Immutable.Record({ id: undefined, name: undefined, email: undefined }); var Message = Immutable.Record({ timestamp: new Date(), sender: undefined, text: "" });
Record 方法接收一個對象,來定義字段和對應的默認數據。
消息的 store 可以使用兩個 list 來跟蹤 users 和 messages:
this.users = Immutable.List(); this.messages = Immutable.List();
實現函數處理每個 payload 類型應該是比較簡單的,比如,當 store 看到一個代表新消息的 payload 時,我們就創建一個新的 record,并放入消息列表:
this.messages = this.messages.push(new Message({ timestamp: payload.timestamp, sender: payload.sender, text: payload.text });
注意:因為數據結構不可變,我們需要把 push 方法的結果賦給 this.messages。
在 React 里,如果我們也使用 immutable-js 數據結構來保存組件的 state,我門可以把 PureRenderMixin 混入到我門所有的組件來縮短重新渲染回路。
這篇文章是翻譯React官方文檔
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87824.html
摘要:組件的性能優化高德納我們應該忘記忽略很小的性能優化,可以說的情況下,過早的優化是萬惡之源,而我們應該關心對性能影響最關鍵的另外的代碼。對多個組件的性能優化當一個組件被裝載更新和卸載時,組件的一序列生命周期函數會被調用。 React組件的性能優化 高德納: 我們應該忘記忽略很小的性能優化,可以說97%的情況下,過早的優化是萬惡之源,而我們應該關心對性能影響最關鍵的另外3%的代碼。...
摘要:數據管理及性能優化統一管理數據這一部份算是重頭戲吧。重復渲染導致卡頓這套的東西在家校群頁面上用得很歡樂,以至于不用怎么寫都沒遇到過什么性能問題。但放到移動端上,我們在列表頁重構的時候就馬上遇到卡頓的問題了。列表頁目前的處理辦法是將值換成。 本文來自于騰訊bugly開發者社區,非經作者同意,請勿轉載,原文地址:http://dev.qq.com/topic/57908... 最近一個季度...
摘要:,谷歌給的一份性能指南和最佳實踐。目前而言,前端社區有三大框架和。隨后重點講述了和兩大前端框架,給出了大量的文章教程和相關資源列表。我認為,使用函數式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個是我訂閱 陳皓老師在極客上的專欄《左耳聽風》...
摘要:,谷歌給的一份性能指南和最佳實踐。目前而言,前端社區有三大框架和。隨后重點講述了和兩大前端框架,給出了大量的文章教程和相關資源列表。我認為,使用函數式編程方式,更加符合后端程序員的思路,而是更符合前端工程師習慣的框架。 showImg(https://segmentfault.com/img/bVbjQAM?w=1142&h=640); 這個是我訂閱 陳皓老師在極客上的專欄《左耳聽風》...
摘要:插件性能優化及個人常用優化方法經常會觸發視覺變化。作用域鏈指的是當前作用于下可用變量的集合,它在各種主流瀏覽器中至少包含兩個部分局部變量的集合和全局變量的集合。在考慮優化時,數值和變量的性能差不多,并且速度顯著優于對象屬性和數組元素。 JavaScript 插件性能優化及個人react常用優化方法 JavaScript 經常會觸發視覺變化。有時是直接通過樣式操作,有時是會產生視覺變化...
摘要:工程實踐立足實踐,提示實際水平內聯函數與性能很多關于性能優化的文章都會談及內聯函數,其也是常見的被詬病為拖慢性能表現的元兇之一不過本文卻是打破砂鍋問到底,論證了內聯函數并不一定就會拖慢性能,過度的性能優化反而會有損于應用性能。 showImg(https://segmentfault.com/img/remote/1460000011481413?w=1240&h=825); 前端每周...
閱讀 3319·2021-11-23 09:51
閱讀 2436·2021-11-09 09:46
閱讀 1476·2019-08-30 15:54
閱讀 3121·2019-08-30 14:22
閱讀 2909·2019-08-29 12:40
閱讀 1629·2019-08-26 10:33
閱讀 1774·2019-08-23 17:09
閱讀 1553·2019-08-23 16:11