成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

【騰訊Bugly干貨分享】React 移動(dòng) web 極致優(yōu)化

suosuopuo / 3253人閱讀

摘要:數(shù)據(jù)管理及性能優(yōu)化統(tǒng)一管理數(shù)據(jù)這一部份算是重頭戲吧。重復(fù)渲染導(dǎo)致卡頓這套的東西在家校群頁(yè)面上用得很歡樂(lè),以至于不用怎么寫(xiě)都沒(méi)遇到過(guò)什么性能問(wèn)題。但放到移動(dòng)端上,我們?cè)诹斜眄?yè)重構(gòu)的時(shí)候就馬上遇到卡頓的問(wèn)題了。列表頁(yè)目前的處理辦法是將值換成。

本文來(lái)自于騰訊bugly開(kāi)發(fā)者社區(qū),非經(jīng)作者同意,請(qǐng)勿轉(zhuǎn)載,原文地址:http://dev.qq.com/topic/57908...

最近一個(gè)季度,我們都在為手Q家校群做重構(gòu)優(yōu)化,將原有那套問(wèn)題不斷的框架換掉。經(jīng)過(guò)一些斟酌,決定使用react 進(jìn)行重構(gòu)。選擇react,其實(shí)也主要是因?yàn)樗哂邢旅娴娜筇匦浴?/p> React的特性

1.Learn once, write anywhere

學(xué)習(xí)React的好處就是,學(xué)了一遍之后,能夠?qū)憌eb, node直出,以及native,能夠適應(yīng)各種紛繁復(fù)雜的業(yè)務(wù)。需要輕量快捷的,直接可以用Reactjs;需要提升首屏?xí)r間的,可以結(jié)合React Server Render;需要更好的性能的,可以上React Native。

但是,這其實(shí)暗示學(xué)習(xí)的曲線非常陡峭。單單是Webpack+ React + Redux就已夠一個(gè)入門(mén)者夠嗆,更何況還要兼顧直出和手機(jī)客戶端。不是一般人能hold住所有端。

2.Virtual Dom

Virtual Dom(下稱(chēng)vd)算是React的一個(gè)重大的特色,因?yàn)镕acebook宣稱(chēng)由于vd的幫助,React能夠達(dá)到很好的性能。是的,F(xiàn)acebook說(shuō)的沒(méi)錯(cuò),但只說(shuō)了一半,它說(shuō)漏的一半是:“除非你能正確的采用一系列優(yōu)化手段”。

3.組件化

另一個(gè)被大家所推崇的React優(yōu)勢(shì)在于,它能令到你的代碼組織更清晰,維護(hù)起來(lái)更容易。我們?cè)趯?xiě)的時(shí)候也有同感,但那是直到我們踩了一些坑,并且漸漸熟悉React+ Redux所推崇的那套代碼組織規(guī)范之后。

那么?

上面的描述不免有些先揚(yáng)后抑的感覺(jué),那是因?yàn)橥鳛镽eact的剛?cè)腴T(mén)者,都會(huì)像我們初入的時(shí)候一樣,對(duì)React滿懷希望,指意它幫我們做好一切,但隨著了解的深入,發(fā)現(xiàn)需要做一些額外的事情來(lái)達(dá)到我們的期待。

對(duì)React的期待

初學(xué)者對(duì)React可能滿懷期待,覺(jué)得React可能完爆其它一切框架,甚至不切實(shí)際地認(rèn)為React可能連原生的渲染都能完爆——對(duì)框架的狂熱確實(shí)會(huì)出現(xiàn)這樣的不切實(shí)際的期待。讓我們來(lái)看看React的官方是怎么說(shuō)的。React官方文檔在Advanced Performanec這一節(jié),這樣寫(xiě)道:

One of the first questions people ask when considering React for a project is whether their application will be as fast and responsive as an equivalent non-React version

顯然React自己也其實(shí)只是想盡量達(dá)到跟非React版本相若的性能。React在減少重復(fù)渲染方面確實(shí)是有一套獨(dú)特的處理辦法,那就是vd,但顯示在首次渲染的時(shí)候React絕無(wú)可能超越原生的速度,或者一定能將其它的框架比下去。因此,我們?cè)谧鰞?yōu)化的時(shí)候,可的期待的東西有:

首屏?xí)r間可能會(huì)比較原生的慢一些,但可以嘗試用React Server Render (又稱(chēng)Isomorphic)去提高效率

用戶進(jìn)行交互的時(shí)候,有可能會(huì)比原生的響應(yīng)快一些,前提是你做了一些優(yōu)化避免了浪費(fèi)性能的重復(fù)渲染。

以手Q家校群功能頁(yè)React重構(gòu)優(yōu)化為例

手Q家校群功能頁(yè)主要由三個(gè)頁(yè)面構(gòu)成,分別是列表頁(yè)、布置頁(yè)和詳情頁(yè)。列表頁(yè)已經(jīng)重構(gòu)完成并已發(fā)布,布置頁(yè)已重構(gòu)完畢準(zhǔn)備提測(cè),詳情頁(yè)正在重構(gòu)。與此同時(shí)我們已完成對(duì)列表頁(yè)的同構(gòu)直出優(yōu)化,并已正在做React Native優(yōu)化的鋪墊。

這三個(gè)頁(yè)面的重構(gòu)其實(shí)覆蓋了不少頁(yè)面的案例,所以還是蠻有代表性的,我們會(huì)將重構(gòu)之中遇到的一些經(jīng)驗(yàn)穿插在文章里論述。

在手Q家校群重構(gòu)之前,其實(shí)我們已經(jīng)做了一版PC家校群。當(dāng)時(shí)將native的頁(yè)面全部web化,直接就采用了React比較常用的全家桶套裝:

構(gòu)建工具 => gulp + webpack

開(kāi)發(fā)效率提升 => redux-dev-tools + hot-reload

統(tǒng)一數(shù)據(jù)管理=> redux

性能提升 => immutable + purerender

路由控制器 => react-router(手Q暫時(shí)沒(méi)采用)

為什么我們?cè)趦?yōu)化的時(shí)候主要講手Q呢?畢竟PC的性能在大部份情況下已經(jīng)很好,在PC上一些存在的問(wèn)題都被PC良好的性能掩蓋下去。手機(jī)的性能不如PC,因此有更多有價(jià)值的東西深挖。開(kāi)發(fā)的時(shí)候我就跟同事開(kāi)玩笑說(shuō):“沒(méi)做過(guò)手機(jī)web優(yōu)化的都真不好意思說(shuō)自己做過(guò)性能優(yōu)化啊“。

構(gòu)建針對(duì)React做的優(yōu)化

我在《性能優(yōu)化三部曲之一——構(gòu)建篇》提出,“通過(guò)構(gòu)建,我們可以達(dá)成開(kāi)發(fā)效率的提升,以及對(duì)項(xiàng)目最基本的優(yōu)化”。在進(jìn)行React重構(gòu)優(yōu)化的過(guò)程中,構(gòu)建對(duì)項(xiàng)目的優(yōu)化作用必不可少。在本文暫時(shí)不贅述,我另外開(kāi)辟了一篇《webpack使用優(yōu)化(react篇)》進(jìn)行具體論述。

開(kāi)發(fā)效率提升工具

在PC端使用Redux的時(shí)候,我們都很喜歡使用Redux-Devtools來(lái)查看Redux觸發(fā)的action,以及對(duì)應(yīng)的數(shù)據(jù)變化。PC端使用的時(shí)候,我們習(xí)慣擺在右邊。但移動(dòng)端的屏幕較少,因此家校群項(xiàng)目使用的時(shí)候放在底部,而且由于性能問(wèn)題,我們?cè)赾onstant里設(shè)一個(gè)debug參數(shù),然后在chrome調(diào)試時(shí)打開(kāi),移動(dòng)端非必須的時(shí)候關(guān)閉。否則,它會(huì)導(dǎo)致移動(dòng)web的渲染比較低下。

數(shù)據(jù)管理及性能優(yōu)化 Redux統(tǒng)一管理數(shù)據(jù)

這一部份算是重頭戲吧。React作為View層的框架,已經(jīng)通過(guò)vd幫助我們解決重復(fù)渲染的問(wèn)題。但vd是通過(guò)看數(shù)據(jù)的前后差異去判斷是否要重復(fù)渲染的,但React并沒(méi)有幫助我們?nèi)プ鲞@層比較。因此我們需要使用一整套數(shù)據(jù)管理工具及對(duì)應(yīng)的優(yōu)化方法去達(dá)成。在這方法,我們選擇了Redux。

Redux整個(gè)數(shù)據(jù)流大體可以用下圖來(lái)描述:

Redux這個(gè)框架的好處在于能夠統(tǒng)一在自己定義的reducer函數(shù)里面去進(jìn)行數(shù)據(jù)處理,在View層中只需要通過(guò)事件去處觸發(fā)一些action就可以改變地應(yīng)的數(shù)據(jù),這樣能夠使數(shù)據(jù)處理和dom渲染更好地分離,而避免手動(dòng)地去設(shè)置state。

在重構(gòu)的時(shí)候,我們傾向于將功能類(lèi)似的數(shù)據(jù)歸類(lèi)到一起,并建立對(duì)應(yīng)的reducer文件對(duì)數(shù)據(jù)進(jìn)行處理。如下圖,是手Q家校群布置頁(yè)的數(shù)據(jù)結(jié)構(gòu)。有些大型的SPA項(xiàng)目可能會(huì)將初始數(shù)據(jù)分開(kāi)在不同的reducer文件里,但這里我們傾向于歸到一個(gè)store文件,這樣能夠清晰地知道整個(gè)文件的數(shù)據(jù)結(jié)構(gòu),也符合Redux想統(tǒng)一管理數(shù)據(jù)的想法。然后數(shù)據(jù)的每個(gè)層級(jí)與reducer文件都是一一對(duì)應(yīng)的關(guān)系。

重復(fù)渲染導(dǎo)致卡頓

這套R(shí)eact + Redux的東西在PC家校群頁(yè)面上用得很歡樂(lè), 以至于不用怎么寫(xiě)shouldComponentUpdate都沒(méi)遇到過(guò)什么性能問(wèn)題。但放到移動(dòng)端上,我們?cè)诹斜眄?yè)重構(gòu)的時(shí)候就馬上遇到卡頓的問(wèn)題了。

什么原因呢?是重復(fù)渲染導(dǎo)致的?。。。。?!

說(shuō)好的React vd可以減少重復(fù)渲染呢??。?!

請(qǐng)別忘記前提條件?。。。?/p>

你可以在每個(gè)component的render里,放一個(gè)console.log("xxx component")。然后觸發(fā)一個(gè)action,在優(yōu)化之前,幾乎全部的component都打出這個(gè)log,表明都重復(fù)渲染了。
更正:可見(jiàn)后面yeatszhang同學(xué)的解釋。

React性能的救星Immutablejs

(網(wǎng)圖,引用的文章太多以致于不知道哪篇才是出處)

上圖是React的生命周期,還沒(méi)熟悉的同學(xué)可以去熟悉一下。因?yàn)槠渲械膕houldComponentUpdate是優(yōu)化的關(guān)鍵。React的重復(fù)渲染優(yōu)化的核心其實(shí)就是在shouldComponentUpdate里面做數(shù)據(jù)比較。在優(yōu)化之前,shouldComponentUpdate是默認(rèn)返回true的,這導(dǎo)致任何時(shí)候觸發(fā)任何的數(shù)據(jù)變化都會(huì)使component重新渲染。這必然會(huì)導(dǎo)致資源的浪費(fèi)和性能的低下——你可能會(huì)感覺(jué)比較原生的響應(yīng)更慢。

這時(shí)你開(kāi)始懷疑這世界——是不是Facebook在騙我。

當(dāng)時(shí)遇到這個(gè)問(wèn)題我的開(kāi)始翻閱文檔,也是在Facebook的Advanced Performance一節(jié)中找到答案:Immutablejs。這個(gè)框架已被吹了有一年多了吧,吹這些框架的人理解它的原理,但不一定實(shí)踐過(guò)——因?yàn)樽鳛橐痪€移動(dòng)端開(kāi)發(fā)者,打開(kāi)它的github主頁(yè)看dist文件,50kb,我就已經(jīng)打退堂鼓了。只是遇到了性能問(wèn)題,我們才再認(rèn)真地去了解一遍。

Immutable這個(gè)的意思就是不可變,Immutablejs就是一個(gè)生成數(shù)據(jù)不可變的框架。一開(kāi)始你并不理解不可變有什么用。最開(kāi)始的時(shí)候Immutable這種數(shù)據(jù)結(jié)構(gòu)是為了解決數(shù)據(jù)鎖的問(wèn)題,而對(duì)于js,就可以借用來(lái)解決前后數(shù)據(jù)比較的問(wèn)題——因?yàn)橥瑫r(shí)Immutablejs還提供了很好的數(shù)據(jù)比較方法——Immutable.is()。小結(jié)一下就是:

Immutablejs本身就能生成不可變數(shù)據(jù),這樣就不需要開(kāi)發(fā)者自己去做數(shù)據(jù)深拷貝,可以直接拿prevProps/prevState和nextProps/nextState來(lái)比較。

Immutable本身還提供了數(shù)據(jù)的比較方法,這樣開(kāi)發(fā)者也不用自己去寫(xiě)數(shù)據(jù)深比較的方法。

說(shuō)到這里,已萬(wàn)事俱備了。那東風(fēng)呢?我們還欠的東風(fēng)就是應(yīng)該在哪里寫(xiě)這個(gè)比較。答案就是shouldComponentUpdate。這個(gè)生命周期會(huì)傳入nextProps和nextState,可以跟component當(dāng)前的props和state直接比較。這個(gè)就可以參考pure-render的做法,去重寫(xiě)shouldComponentUpdate,在里面寫(xiě)數(shù)據(jù)比較的邏輯。

其中一位同事polarjiang利用Immutablejs的is方法,參考pure-render-decorator寫(xiě)了一個(gè)immutable-pure-render-decorator。

那具體怎么使用immutable + pure-render呢?

對(duì)于immutable,我們需要改寫(xiě)一下reducer functions里面的處理邏輯,一律換成Immutable的api。

至于pure-render,若是es5寫(xiě)法,可以用使mixin;若是es6/es7寫(xiě)法,需要使用decorator,在js的babel loader里面,新增plugins: [‘transform-decorators-legacy’]。其es6的寫(xiě)法是:

@pureRender
export default class List extends Component { ... }
Immutablejs帶來(lái)的一些問(wèn)題

不重新渲染

你可能會(huì)想到Immutable能減少無(wú)謂的重新渲染,但可能沒(méi)想過(guò)會(huì)導(dǎo)致頁(yè)面不能正確地重新渲染。目前列表頁(yè)在老師進(jìn)入的時(shí)候是有2個(gè)tab的,tab的切換會(huì)讓列表也切換。目前手Q的列表頁(yè)學(xué)習(xí)PC的列表頁(yè),兩個(gè)列表共用一套dom結(jié)構(gòu)(因?yàn)槌俗鳂I(yè)布置者名字之外,兩個(gè)列表一模一樣)。上了Immutablejs之后,當(dāng)碰巧“我發(fā)布的“列表和”全部“列表開(kāi)頭的幾個(gè)作業(yè)都是同一個(gè)人布置的時(shí)候,列表切換就不重新渲染了。

引入immutable和pureRender后,render里的JSX注意一定不要有同樣的key(如兩個(gè)列表,有重復(fù)的數(shù)據(jù),此時(shí)以數(shù)據(jù)id來(lái)作為key就不太合適,應(yīng)該要用數(shù)據(jù)id + 列表類(lèi)型作為key),會(huì)造成不渲染新數(shù)據(jù)情況。列表頁(yè)目前的處理辦法是將key值換成id + listType。

(列表頁(yè)兩個(gè)列表的切換)

這樣寫(xiě)除了保證在父元素那一層知曉數(shù)據(jù)(key值)不同需要重新渲染之外,也保證了React底層渲染知道這是兩組不同的數(shù)據(jù)。在React源文件里有一個(gè)ReactChildReconciler.js主要是寫(xiě)children的渲染邏輯。其中的updateChildren里面有具體如何比較前后children,然后再?zèng)Q定是否要重新渲染。在比較的時(shí)候它調(diào)用了shouldUpdateReactComponent方法。我們看到它有對(duì)key值做比較。在兩個(gè)列表中有不同的key,在數(shù)據(jù)相似的情況下,能保證兩者切換的時(shí)候能重新渲染。

function shouldUpdateReactComponent(prevElement, nextElement) {
  var prevEmpty = prevElement === null || prevElement === false;
  var nextEmpty = nextElement === null || nextElement === false;
  if (prevEmpty || nextEmpty) {
    return prevEmpty === nextEmpty;
  }

  var prevType = typeof prevElement;
  var nextType = typeof nextElement;
  if (prevType === "string" || prevType === "number") {
    return nextType === "string" || nextType === "number";
  } else {
    return nextType === "object" && prevElement.type === nextElement.type && prevElement.key === nextElement.key;
  }
}

Immutablejs太大了

上文也提到Immutablejs編譯后的包也有50kb。對(duì)于PC端來(lái)說(shuō)可能無(wú)所謂,網(wǎng)速足夠快,但對(duì)于移動(dòng)端來(lái)說(shuō)壓力就大了。有人寫(xiě)了個(gè)seamless-immutable,算是簡(jiǎn)易版的Immutablejs,只有2kb,只支持Object和Array。

但其實(shí)數(shù)據(jù)比較邏輯寫(xiě)起來(lái)也并不難,因此再去review代碼的時(shí)候,我決定嘗試自己寫(xiě)一個(gè),也是這個(gè)決定讓我發(fā)現(xiàn)了更多的奧秘。

針對(duì)React的這個(gè)數(shù)據(jù)比較的深比較deepCompare,要點(diǎn)有2個(gè):

盡量使傳入的數(shù)據(jù)扁平化一點(diǎn)

比較的時(shí)候做一些限制,避免溢出棧

先上一下列表頁(yè)的代碼,如下圖。這里當(dāng)時(shí)是學(xué)習(xí)了PC家校群的做法,將component作為props傳入。這里的封裝的是滾動(dòng)檢測(cè)的邏輯,而則是列表頁(yè)的渲染,是列表為空的時(shí)候展示的內(nèi)容,是列表底部加載的顯示橫條。

針對(duì)deepCompare的第1個(gè)要點(diǎn),扁平化數(shù)據(jù),我們很明顯就能定位出其中一個(gè)問(wèn)題了。例如,我們傳入了props.hw,這個(gè)props包括了兩個(gè)列表的數(shù)據(jù)。但這樣的結(jié)構(gòu)就會(huì)是這樣

props.hw = {
    listMine: [
        {...}, {...}, ...
    ],
    listAll: [
        {...}, {...}, ...
    ],
}

但如果我們提前在傳入之前判斷當(dāng)前在哪個(gè)列表,然后傳入對(duì)應(yīng)列表的數(shù)量,則會(huì)像這樣:

props.hw = 20;

兩者比較起來(lái),顯示是后者簡(jiǎn)單得多。

針對(duì)deepCompare第2點(diǎn),限制比較的條件。首先讓我們想到的是比較的深度。一般而言,對(duì)于Object和Array數(shù)據(jù),我們都需要遞歸去進(jìn)行比較,出于性能的考慮,我們都會(huì)限制比較的深度。

除此之外,我們回顧一下上面的代碼,我們將幾個(gè)React component作為props傳進(jìn)去了,這會(huì)在shouldComponentUpdate里面顯示出來(lái)。這些component的結(jié)構(gòu)大概如下:

$$typeof // 類(lèi)型
_owner // 父組件
_self: // 僅開(kāi)發(fā)模式出現(xiàn)
_source: //  僅開(kāi)發(fā)模式出現(xiàn)
_store //  僅開(kāi)發(fā)模式出現(xiàn)
key // 組件的key屬性值
props // 從傳入的props
ref // 組件的ref屬性值
type 本組件ReactComponent

因此,針對(duì)component的比較,有一些是可以忽略的,例如$$typeof, _store, _self, _source, _owner。type這個(gè)比較復(fù)雜,可以比較,但僅限于我們定好的比較深度。如果不做這些忽略,這個(gè)深比較將會(huì)比較消耗性能。關(guān)于這個(gè)deepCompare的代碼,我放在了pure-render-deepCompare-decorator。

不過(guò)其實(shí),將component當(dāng)作props傳入更為靈活,而且能夠增加組件的復(fù)用性,但從上面看來(lái),是比較消耗性能的。看了官方文檔之后,我們嘗試換種寫(xiě)法,主要就是采用包裹的做法,然后用this.props.children在里面渲染,并將, 抽出來(lái)。

本以為React可能會(huì)對(duì)children這個(gè)props有什么特殊處理,但它依然是將children當(dāng)作props,傳入shouldComponentUpdate,這就迫使父元素要去判斷是否要重新渲染,進(jìn)而跳到子無(wú)素再去判斷是否進(jìn)一步進(jìn)行渲染。

究竟要不要去做這重判斷呢?針對(duì)列表頁(yè)這種情況,我們覺(jué)得可以暫時(shí)不做,由于包裹的元素不多,可以先重復(fù)渲染,然后再交由子元素自己再去判斷。這樣我們對(duì)pure-render-deepCompare-decorator要進(jìn)行一些修改,當(dāng)輪到props.children判斷的時(shí)候,我們要求父元素直接重新渲染,這樣就能交給子元素去做下一步的處理。

如果包裹的只有還好,如果還有像, 甚至其它更多的子元素,那重新渲染會(huì)觸發(fā)其它子元素去運(yùn)算,判斷自己是否要做重新渲染,這就造成了浪費(fèi)。react的官方論壇上已經(jīng)有人提出,React的將父子元素的重復(fù)渲染的決策都放在shouldComponentUpdate,可能導(dǎo)致了耦合Shouldcomponentupdate And Children。

lodash.merge可以解決大部份場(chǎng)景

(此段更新于2016年6月30日)由于immutable的大小問(wèn)題一直縈繞頭上,久久不得散去,因此再去找尋其它的方案。后面決定嘗試一下lodash.merge,并用上之前自己寫(xiě)的pureRender。在渲染性能上還可以接受,在僅比immutable差一點(diǎn)點(diǎn)(后面會(huì)披露具體數(shù)據(jù)),但卻帶來(lái)了30kb的減包。

性能優(yōu)化小Tips

這里歸納了一些其它性能優(yōu)化的小Tips。

1. 請(qǐng)慎用setState,因其容易導(dǎo)致重新渲染

既然將數(shù)據(jù)主要交給了Redux來(lái)管理,那就盡量使用Redux管理你的數(shù)據(jù)和狀態(tài)state,除了少數(shù)情況外,別忘了shouldComponentUpdate也需要比較state。

2. 請(qǐng)將方法的bind一律置于constructor

Component的render里不動(dòng)態(tài)bind方法,方法都在constructor里bind好,如果要?jiǎng)討B(tài)傳參,方法可使用閉包返回一個(gè)最終可執(zhí)行函數(shù)。如:showDelBtn(item) { return (e) => {}; }。如果每次都在render里面的jsx去bind這個(gè)方法,每次都要綁定會(huì)消耗性能。

3. 請(qǐng)只傳遞component需要的props

傳得太多,或者層次傳得太深,都會(huì)加重shouldComponentUpdate里面的數(shù)據(jù)比較負(fù)擔(dān),因此,也請(qǐng)慎用spread attributes()。

4. 請(qǐng)盡量使用const element

這個(gè)用法是工業(yè)聚在React討論微信群里教會(huì)的,我們可以將不怎么變動(dòng),或者不需要傳入狀態(tài)的component寫(xiě)成const element的形式,這樣能加快這個(gè)element的初始渲染速度。

路由控制與拆包

當(dāng)項(xiàng)目變得更大規(guī)模與復(fù)雜的時(shí)候,我們需要設(shè)計(jì)成SPA,這時(shí)路由管理就非常重要了,這使特定url參數(shù)能夠?qū)?yīng)一個(gè)頁(yè)面。

PC家校群整個(gè)設(shè)計(jì)是一個(gè)中型的SPA,當(dāng)js bundle太大的時(shí)候,需要拆分成幾個(gè)小的bundle,進(jìn)行異步加載。這時(shí)可以用到webpack的異步加載打包功能,require。

在重構(gòu)手Q家校群布置頁(yè)的時(shí)候,我們有不少的浮層,列表有布置頁(yè)內(nèi)容主浮層、同步到多群浮層、科目管理浮層以及指定群成員浮層。這些完全可以使用react-router進(jìn)行管理。但是由于當(dāng)時(shí)一早使用了Immutablejs,js bundle已經(jīng)比較大,我們就不打算使用react-router了。但后面仍然發(fā)現(xiàn)包比重構(gòu)前要大一些,因此為了保證首屏?xí)r間不慢于重構(gòu)前,我們希望在不用react-router的情況下進(jìn)行分包,其實(shí)也并不難,如下面2幅圖:

首先在切換浮層方法里面,使用require.ensure,指定要加載哪個(gè)包。
在setComponent方法里,將component存在state里面。
在父元素的渲染方法里,當(dāng)state有值的時(shí)候,就會(huì)自動(dòng)渲染加載回來(lái)的component。

性能數(shù)據(jù) 首屏可交互時(shí)間

目前只有列表頁(yè)發(fā)布外網(wǎng)了,我們比較了優(yōu)化前后的首屏可交互時(shí)間,分別有18%和5.3%的提升。

渲染FPS

更新于2016年7月2日

Android

React重構(gòu)后第一版,當(dāng)時(shí)還沒(méi)做任何的優(yōu)化,發(fā)現(xiàn)平均FPS只有22(雖然Android的肉眼感受不出來(lái)),而后面使用Immutable或者Lodash.merge都非常接近,能達(dá)到42或以上。而手機(jī)QQ可接受的FPS最少值是30FPS。因此使用Immutable和Lodash.merge的優(yōu)化還是相當(dāng)明顯的。

重構(gòu)后第一版

Immutable

Lodash.merge

iOS

在iOS上的fps差距尤為明顯。重構(gòu)后第一版,拉了大概5屏之后,肉眼會(huì)有卡頓的感覺(jué),拉到了10屏之后,數(shù)據(jù)開(kāi)始掉到了20多30。而Immutable和Lodash.merge則大部份時(shí)間保持在50fps以上,很多時(shí)候還能達(dá)到非常流暢的60fps。

重構(gòu)后第一版

Immutable

Lodash.merge

Chrome模擬器

用Chrome模擬器也能看出一些端倪。在Scripting方面,Immutable和Lodash.merge的耗時(shí)是最少的,約700多ms,而重構(gòu)后的第一版則需要1220ms。Lodash.merge在rendering和painting上則沒(méi)占到優(yōu)勢(shì),但I(xiàn)mmutable則要比其它兩個(gè)要少30% - 40%。由于測(cè)試的時(shí)候是在PC端,PC端的性能又極好,所以不管是肉眼,還是數(shù)據(jù),對(duì)于不是很復(fù)雜的需求,總體的渲染性能看不出非常明顯的差距。

重構(gòu)后第一版

Immutable

Lodash.merge

從上面的數(shù)據(jù)看來(lái),在移動(dòng)端使用Immutable和Lodash.merge相對(duì)于不用,會(huì)有較大的性能優(yōu)勢(shì),但I(xiàn)mmutable相對(duì)于Lodash.merge在我們需求情景下暫時(shí)沒(méi)看出明顯的優(yōu)勢(shì),筆者估計(jì)可能是由于項(xiàng)目數(shù)據(jù)規(guī)模不大,結(jié)構(gòu)不復(fù)雜,因此Immutable的算法優(yōu)勢(shì)并沒(méi)有充分發(fā)揮出來(lái)。

測(cè)試注明

Android端測(cè)試FPS是使用了騰訊開(kāi)發(fā)的GT隨身調(diào)。而iOS則使用了Macbook里xCode自帶的instrument中的animation功能。Chrome模擬器則使用了Chrome的timeline。測(cè)試的方式是勻速滾動(dòng)列表,拉出數(shù)據(jù)進(jìn)行渲染。

React性能優(yōu)化軍規(guī)

我們?cè)陂_(kāi)發(fā)的過(guò)程中,將上面所論述的內(nèi)容,總結(jié)成一個(gè)基本的軍規(guī),銘記于心,就可以保證React應(yīng)用的性能不至于太差。

渲染相關(guān)

提升級(jí)項(xiàng)目性能,請(qǐng)使用immutable(props、state、store)

請(qǐng)pure-render-decorator與immutablejs搭配使用

請(qǐng)慎用setState,因其容易導(dǎo)致重新渲染

謹(jǐn)慎將component當(dāng)作props傳入

請(qǐng)將方法的bind一律置于constructor

請(qǐng)只傳遞component需要的props,避免其它props變化導(dǎo)致重新渲染- - (慎用spread attributes)

請(qǐng)?jiān)谀阆Ml(fā)生重新渲染的dom上設(shè)置可被react識(shí)別的同級(jí)唯一key,否則react在某些情況可能不會(huì)重新渲染。

請(qǐng)盡量使用const element

tap事件

簡(jiǎn)單的tap事件,請(qǐng)使用react-tap-event-plugin 開(kāi)發(fā)環(huán)境時(shí),最好引入webpack的環(huán)境變量(僅在開(kāi)發(fā)環(huán)境中初始化),在container中初始化。生產(chǎn)環(huán)境的時(shí)候,請(qǐng)將plugin跟react打包到一起(需要打包在一起才能正常使用,因?yàn)閜lugin對(duì)react有好多依賴(lài)),外鏈引入。

目前參考了這個(gè)項(xiàng)目的打包方案:https://github.com/hartmamt/r...
Facebook官方issue: https://github.com/facebook/r...
React-tap-event-plugin github: https://github.com/zilverline...

復(fù)雜的tap事件,建議使用tap component 家校群列表頁(yè)的每個(gè)作業(yè)的tap交互都比較復(fù)雜,出了普通的tap之外,還需要long tap和swipe。因此我們只好自己封裝了一個(gè)tap component

Debug相關(guān)

移動(dòng)端請(qǐng)慎用redux-devtools,易造成卡頓

Webpack慎用devtools的inline-source-map模式 使用此模式會(huì)內(nèi)聯(lián)一大段便于定位bug的字符串,查錯(cuò)時(shí)可以開(kāi)啟,不是查錯(cuò)時(shí)建議關(guān)閉,否則開(kāi)發(fā)時(shí)加載的包會(huì)非常大。

其它

慎用太新的es6語(yǔ)法。 Object.assign等較新的類(lèi)庫(kù)避免在移動(dòng)端上使用,會(huì)報(bào)錯(cuò)。 Object.assign目前使用object-assign包?;蛘呤褂胋abel-plugin-transform-object-assign插件。會(huì)轉(zhuǎn)換成一個(gè)extends的函數(shù):

var _extends = ...;
_extends(a, b);

注意Object.assign是淺拷貝 Object.assign是淺拷貝,若數(shù)據(jù)結(jié)構(gòu)層次較深的時(shí)候會(huì)拷貝失敗,直接回傳原本的object reference,此處推薦lodash.merge。

如有錯(cuò)誤,請(qǐng)斧正!

PS: 要看效果得將一個(gè)QQ群組轉(zhuǎn)換成家校群,可到此網(wǎng)址進(jìn)行轉(zhuǎn)換(手Q/PC都可以訪問(wèn)):http://qun.qq.com/homework/。
轉(zhuǎn)換之后,可以通過(guò)QQ群的加號(hào)面板,或者群資料卡進(jìn)入。

更多精彩內(nèi)容歡迎關(guān)注bugly的微信公眾賬號(hào):

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86402.html

相關(guān)文章

  • 7月份前端資源分享

    摘要:更多資源請(qǐng)文章轉(zhuǎn)自月份前端資源分享的作用數(shù)組元素隨機(jī)化排序算法實(shí)現(xiàn)學(xué)習(xí)筆記數(shù)組隨機(jī)排序個(gè)變態(tài)題解析上個(gè)變態(tài)題解析下中的數(shù)字前端開(kāi)發(fā)筆記本過(guò)目不忘正則表達(dá)式聊一聊前端存儲(chǔ)那些事兒一鍵分享到各種寫(xiě)給剛?cè)腴T(mén)的前端工程師的前后端交互指南物聯(lián)網(wǎng)世界的 更多資源請(qǐng)Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github.com/jsfr...

    pingan8787 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<