跳到主要內容

Marketplace 中的 React Native 效能

·5 分鐘閱讀
Facebook 軟體工程師

React Native 已在 Facebook 系列的多個應用程式中的多個位置使用,包括主要 Facebook 應用程式中的頂層標籤。本文的重點是一個高度可見的產品,Marketplace。它在十幾個國家/地區提供,讓使用者能夠發現其他使用者提供的產品和服務。

在 2017 年上半年,透過 Relay 團隊、Marketplace 團隊、Mobile JS Platform 團隊和 React Native 團隊的共同努力,我們將 Android Year Class 2010-11 裝置的 Marketplace 互動時間 (TTI) 縮短了一半。Facebook 歷來將這些裝置視為低階 Android 裝置,它們在任何平台或裝置類型上的 TTI 都是最慢的。

典型的 React Native 啟動看起來像這樣

免責聲明:比例不具代表性,並且會因 React Native 的配置和使用方式而異。

我們首先初始化 React Native 核心(又稱「橋接器」),然後執行產品特定的 JavaScript,這決定了 React Native 將在原生處理時間中呈現哪些原生檢視。

不同的方法

我們早期犯下的錯誤之一是讓 Systrace 和 CTScan 驅動我們的效能工作。這些工具幫助我們在 2016 年找到了許多垂手可得的成果,但我們發現 Systrace 和 CTScan 都不能代表生產情境,也無法模擬在實際環境中發生的情況。時間分解的比例通常不正確,有時甚至完全失準。在極端情況下,我們預期需要幾毫秒才能完成的事情實際上需要數百甚至數千毫秒。儘管如此,CTScan 仍然很有用,我們發現它在迴歸問題影響生產環境之前,能夠捕捉到三分之一的迴歸問題。

在 Android 上,我們將這些工具的缺點歸因於以下事實:1) React Native 是一個多執行緒框架,2) Marketplace 與大量複雜的檢視(例如 Newsfeed 和其他頂層標籤)共置,以及 3) 計算時間差異很大。因此,這半年,我們讓生產測量和分解幾乎驅動了我們所有的決策和優先順序。

生產檢測之路

表面上看來,檢測生產環境可能很簡單,但事實證明這是一個相當複雜的過程。它需要多次迭代循環,每次 2-3 週;這是因為將提交內容發佈到主分支、將應用程式推送到 Play 商店,以及收集足夠的生產樣本以對我們的工作有信心都存在延遲。每個迭代循環都涉及發現我們的分解是否準確、它們是否具有正確的粒度級別,以及它們是否正確地加總到整個時間跨度。我們不能依賴 alpha 和 beta 版本,因為它們不能代表一般使用者。本質上,我們非常乏味地基於數百萬個樣本的總和,建構了一個非常準確的生產追蹤。

我們仔細驗證分解中的每一毫秒是否正確加總到其父指標的原因之一是,我們很早就意識到我們的檢測中存在差距。事實證明,我們最初的分解並沒有考慮到執行緒跳躍造成的停頓。執行緒跳躍本身並不昂貴,但跳躍到正在執行工作的繁忙執行緒則非常昂貴。我們最終透過在正確的時刻灑上 Thread.sleep() 呼叫,在本地重現了這些阻塞,並且我們透過以下方式設法修復了它們

  1. 移除我們對 AsyncTask 的依賴性,
  2. 取消強制在 UI 執行緒上初始化 ReactContext 和 NativeModules,以及
  3. 移除在初始化時測量 ReactRootView 的依賴性。

總之,移除這些執行緒阻塞問題將啟動時間縮短了 25% 以上。

生產指標也挑戰了我們之前的一些假設。例如,我們過去常常在啟動路徑上預先載入許多 JavaScript 模組,假設將模組共置在一個套件中會降低其初始化成本。然而,預先載入和共置這些模組的成本遠遠超過了收益。透過重新配置我們的內聯 require 黑名單並從啟動路徑中移除 JavaScript 模組,我們能夠避免載入不必要的模組,例如 Relay Classic(當只需要 Relay Modern 時)。如今,我們的 RUN_JS_BUNDLE 分解速度提高了 75% 以上。

我們也透過調查產品特定的原生模組找到了優勢。例如,透過延遲注入原生模組的依賴項,我們將該原生模組的成本降低了 98%。透過消除 Marketplace 啟動與其他產品的競爭,我們將啟動時間縮短了相當的間隔。

最棒的是,許多這些改進廣泛適用於使用 React Native 建置的所有螢幕。

結論

人們認為 React Native 啟動效能問題是由 JavaScript 速度慢或網路時間過高引起的。雖然加快 JavaScript 等速度會使 TTI 降低相當可觀的總和,但這些因素各自對 TTI 的貢獻百分比遠低於之前的預期。

到目前為止的教訓是測量、測量、再測量! 有些優勢來自將執行時間成本轉移到建置時間,例如 Relay Modern 和 Lazy NativeModules。其他優勢來自於更聰明地並行處理程式碼或移除無效程式碼來避免工作。還有一些優勢來自於 React Native 的重大架構變更,例如清理執行緒阻塞。效能沒有萬能的解決方案,更長期的效能提升將來自於漸進式的檢測和改進。不要讓認知偏見影響您的決策。相反,請仔細收集和解釋生產資料,以指導未來的工作。

未來計畫

從長遠來看,我們希望 Marketplace TTI 能夠與使用原生技術建置的類似產品相媲美,並且總體而言,React Native 效能能夠與原生效能相提並論。更重要的是,儘管這半年我們大幅降低了約 80% 的橋接器啟動成本,但我們計劃透過 Prepack 等專案和更多建置時間處理,將 React Native 橋接器的成本降至接近於零。