看Facebook是如何優化React Native性能

原文出處: facebook   譯文出處:@Siva海浪高   react

該文章翻譯自Facebook官方博客,傳送門git

React Native 容許咱們運用 React 和 Relay 提供的聲明式的編程模型,寫JavaScript來構建咱們的 iOS 和 Android 的應用。這樣的作法使得咱們的代碼更精簡,更容易理解和閱讀,這些代碼還能夠在多個平臺共享。咱們也能夠加快迭代速度(由於在開發時不用等待漫長的編譯。使用React Native,咱們能夠發佈更快,打磨更多細節,讓應用運行的更流暢。這其中優化性能是咱們工做的一大重要部分,接下來說述 Facebook 如何使應用性能足足提高兩倍的故事~github

爲何要加快?

當應用運行的更快,內容加載的更迅速,就意味着用戶能夠有更多時間來使用應用,流暢的動畫讓用戶更加享受的使用應用。在新型市場中,2G網絡和幾年前的機型仍是主力。這時那些性能良好的和那些運行卡頓就有很大差異了。web

自從發佈了 iOS 和 Android 版本的 React Native 後,咱們團隊一直在諸如 提高列表視圖的滾動性能,優化內存佔有,讓 UI 界面更具響應性和加快應用啓動速度 上作了很多工做。這其中應用啓動關乎初次印象和是框架其餘部分的壓力源頭,因此它是要解決的頭等難題。編程

量化一切

咱們把Facebook的iOS版中的事件主頁用RN從新實現(在更多標籤頁下點擊事件進入查看)。這是個很是好的用於測試性能的例子,由於原生版已經作了大量的優化工做,並且該頁面也是很是好的典型列表交互的例子。react-native

接下來,咱們自動化的 CT-Scan 性能測試來幫助咱們自動定位到咱們須要到的標籤頁。而後反覆打開和關閉事件主頁50次。在每次交互中,咱們可以記錄下從點擊事件按鈕到事件主頁可以被完整顯示的時間,咱們也添加更多詳細的性能埋點來告訴咱們啓動過程哪些步驟是緩慢或消耗CPU的緩存

下面是咱們記錄和測量的一些步驟的大體描述:性能優化

1 原生啓動:初始化JavaScript虛擬機和其餘一些原生模塊(如磁盤緩存,網絡,UI管理器等)服務器

2 JS初始化和依賴加載:從手機存儲中讀取被壓縮的JS代碼,加載到JavaScript虛擬機,從而解析和產生字節碼,加載相關的依賴網絡

3 取數據前:加載和執行事件主頁的應用代碼,構建Relay的查詢語句,而後觸發取數據。

4 取數據:從手機磁盤緩存讀取數據

5 JS渲染:初始化全部相關的React組件,把它們發送到原生的UI管理器模塊來顯示。

6 原生渲染:在shadow線程中先經過根據 FlexBox 佈局計算視圖大小。而後在主線程中建立和定位這些視圖。

咱們根據於此的黃金法則是:永遠不要忘了迴歸測試。咱們持續的運行它來追蹤性能提高和功能迴歸。開發者在提交改動的代碼以前用它對特定的提交作運行和詳細的性能分析。其餘的一些測試也須要被一樣的方式創建來衡量諸如功能性能和內存使用等

啓動時發生了什麼

當咱們設置好自動性能追蹤,咱們須要一個工具來給咱們更多細節來決定啓動過程當中的那些部分須要優化。咱們在咱們框架裏添加詳細的啓動/暫停的性能錨點,收集數據,使用 catapult 查看器來定位熱點和阻塞線程間交互的。也能夠從開發者菜單下觸發開始對咱們應用的性能分析。

在RN中,代碼是在JavaScript線程中執行的。每次你要寫數據到磁盤,在一次網絡請求,或者取一些其餘原生的資源(如攝像機),你的代碼都須要調用原生模塊。當你要渲染力你的 React 組件,它們會被轉發到界面管理器的原生模塊中,它在主線程中來執行佈局和建立相應的視圖。橋協議來轉發請求到原生模塊和被回調到你的JS代碼(若是須要)。在RN中,全部原生的調用必須是異步的來避免阻塞主線程和JS線程。

在下面的事件組件的啓動可視化圖中,咱們能夠看到應用在 JS 隊列中運行,爲了顯示事件列表,觸發了相關的緩存讀取(在本地存儲隊列中被異步觸發)。一旦它取得了緩存數據,應用在 JS 隊列用 React 渲染事件單元格,接着又傳給柵格隊列來佈局和最終傳給主隊列來建立視圖顯示。這個例子展現了多個緩存讀取(組合成單個經常使用讀取操做能夠作到更快)和一些React在JS線程上的渲染操做能夠被統一合併。

性能提高

下面是那些咱們在實施過程當中最重要的性能和時序安排的提高作法,同時配有對應代碼提交的連接。

啓動時少作些

安排合適時機執行

  • 懶加載
  • Relay的增量緩存讀取:Relay一開始是web項目而生因此僅僅把請求響應放在內存中 – 要從磁盤讀取的第一個請求的緩存響應須要從磁盤中讀取所有的緩存到內存中。經過只讀取知足特定查詢請求的緩存,咱們能夠顯著減小 I/O 負載和原生到JS橋的流量。
  • 不用批量橋協議調用,要批量Relay調用:一開始咱們認爲經過把JS請求批量發送給原生模塊能夠減小調用原生到JS橋的負載,可是性能分析告訴咱們JS和原生間的橋調用根本不是性能瓶頸。事實上,UI界面或緩存讀取的批量操做的延遲也會延遲原生線程的操做,從而影響應用性能。在其餘case上,注入Relay用於拉取多個鍵值數據的緩存讀取,經過批處理能夠有顯著提高。
  • 更早的界面填充
  • 懶加載原生模塊
  • 對文本組件的觸摸作懶綁定:綁定觸摸事件回調會須要很多時間。因此咱們如今僅僅先綁定觸摸開始事件touch down event(就是當你第一次觸摸對象時)而後只當你觸摸對象後纔開始綁定其餘回調函數,而不是一開始就所有綁定對調
  • 延遲流行事件的查詢:

爲光速作準備

幾個月前,事件主頁的啓動在 iPhone5 上須要2秒。通過咱們在RN上的大量性能優化工做,在倫敦,門洛帕克和紐約的RN,React和Relay團隊,事件主頁的啓動被加快了一倍。並且大部分咱們實施的優化是在RN的框架層的,這就意味着開發者們的RN應用也會自動得益於這些工做(當他們把應用遷移到最新版本的RN下

這些優化才僅僅是個開始:咱們會繼續在整個棧的各個部分都開展工做,從JavaScript代碼解析時間到數據拉取性能。同時,大家也能夠給社區貢獻,學習如何讓應用更快,在社區論壇提出你可能遇到的任何問題。QQ技術交流羣290551701

相關文章
相關標籤/搜索