React Native 底層原理與實現(xiàn)流程深度解析

引言

React Native 是 Facebook 開發(fā)的一個開源框架,允許開發(fā)者使用 JavaScript 和 React 構(gòu)建跨平臺移動應(yīng)用。它承諾"一次學(xué)習(xí),隨處編寫"(Learn once, write anywhere),讓 Web 開發(fā)者能夠利用現(xiàn)有技能開發(fā)移動應(yīng)用,同時保持原生應(yīng)用的性能和用戶體驗。本報告將深入探討 React Native 的底層原理、實現(xiàn)流程和調(diào)用邏輯,幫助開發(fā)者更全面地理解這一框架的工作機制。

React Native 的整體架構(gòu)

React Native 的整體架構(gòu)可以分為三個主要部分:JS域、Native域以及負責兩個域之間通信的C++ Bridge。這一架構(gòu)設(shè)計使得開發(fā)者可以使用JavaScript編寫業(yè)務(wù)邏輯,同時利用原生組件實現(xiàn)高性能的UI渲染。

三層架構(gòu)設(shè)計

React Native 的核心架構(gòu)可以概括為三層結(jié)構(gòu):

  • JS層:運行在JavaScriptCore上的JavaScript代碼,處理業(yè)務(wù)邏輯和組件渲染

  • Shadow層:包含React Native的核心邏輯和組件定義

  • Native層:平臺相關(guān)的原生代碼,負責實際的UI渲染和系統(tǒng)交互

這種分層設(shè)計使得React Native能夠同時保持開發(fā)效率和運行性能[11]。

React Native 的主要特點

React Native 具有以下顯著特點:

  1. 跨平臺開發(fā):使用 Virtual DOM 技術(shù),只需編寫一套代碼,就可以將應(yīng)用打包為不同平臺的App,大幅提高開發(fā)效率[49]。

  2. 性能優(yōu)化:由于 React Native 使用的組件是對原生 API 的封裝,體驗和性能足以媲美原生應(yīng)用[49]。

  3. 熱更新能力:React Native 的產(chǎn)物是 bundle 文件,本質(zhì)上是 JS 代碼,應(yīng)用啟動時會從服務(wù)器獲取最新的 bundle 文件,實現(xiàn)無需重新下載應(yīng)用即可更新功能[49]。

  4. 開發(fā)效率高:相比原生開發(fā),JavaScript 學(xué)習(xí)成本低、語法靈活,允許 Web 開發(fā)者更多地基于現(xiàn)有經(jīng)驗開發(fā) App[46]。

React Native 的啟動流程

React Native 的啟動流程是理解其工作原理的關(guān)鍵。以下是 React Native 啟動的主要步驟:

創(chuàng)建 ReactRootView

ReactRootView 是 React Native 的根視圖,負責監(jiān)聽標準 Android 的 View 相關(guān)各種事件及事件分發(fā)和子 View 渲染等。在創(chuàng)建 ReactRootView 時,會初始化 ReactInstanceManager 和 ReactContext 實例[36]。

創(chuàng)建 ReactInstanceManager

ReactInstanceManager 是大內(nèi)總管接口類,提供一個構(gòu)造者模式的初始化 Builder。它是 React Native 啟動流程的核心入口,負責管理 JS 和 Native 交互,做中轉(zhuǎn)角色[36]。

創(chuàng)建 ReactContext

ReactContext 是 React Native 的上下文對象,包含 ReactInstanceManager 創(chuàng)建的 NativeModuleRegistry 和 JavaScriptModuleRegistry 映射表。ReactContext 在 ReactInstanceManager 創(chuàng)建后被關(guān)聯(lián)到 ReactInstanceManager 實例上[36]。

加載 JS Bundle

React Native 會加載打包好的 JS Bundle 文件,這個文件包含了應(yīng)用的業(yè)務(wù)邏輯和組件定義。加載完成后,通過調(diào)用 AppRegistry.runApplication 方法啟動應(yīng)用[36]。

渲染組件

在啟動完成后,React Native 會根據(jù)注冊的組件進行渲染。組件會被包裹在 AppContainer 中,AppContainer 用于外面包圍一些 Debug 用的工具(如紅盒)[50]。

React Native 的通信機制

React Native 的核心在于其跨語言通信能力,它通過 Bridge 進行原生端和 JavaScript 之間的交互。以下是 React Native 的通信機制詳解:

Bridge 架構(gòu)

在 React Native 中,原生端和 JavaScript 交互是通過 Bridge 進行的。Bridge 的作用是給 React Native 內(nèi)嵌的 JS Engine 提供原生接口的擴展供 JS 調(diào)用。所有的本地存儲、圖片資源訪問、圖形圖像繪制、3D 加速、網(wǎng)絡(luò)訪問、震動效果、NFC、原生控件繪制、地圖、定位、通知等都是通過 Bridge 封裝成 JS 接口以后注入 JS Engine 供 JS 調(diào)用[46]。

Native 調(diào)用 JS

在 React Native 里面,JS 的方法可以通過 global.batchedBridge.callFunctionReturnFlushedQueue 這個方法進行調(diào)用。在 Native 側(cè),只需將 React Native 里面的 global.batchedBridge 對象中的方法和 Native 側(cè)的 JSIExecutor 方法進行綁定(本質(zhì)上 Native 指針指向 JS 函數(shù))[46]。

Native 側(cè)的 callFunctionReturnFlushedQueue 主要做了以下事情:

  • 通過 moduleid 和 methodid 完成方法的調(diào)用,通過這兩個參數(shù)可以找到 JS 側(cè)定義的方法模塊。

JS 調(diào)用 Native

當 JS 調(diào)用 Native 模塊的時候,會調(diào)用一個 Native 暴露出來的全局方法:nativeFlushQueueImmediate,并通過傳入要調(diào)用的 moduleName、methodName、callback 參數(shù)給這個方法,然后這個方法再通知給 Native 側(cè)找到相應(yīng)的模塊并執(zhí)行[46]。

React Native 中的線程模型

React Native Android 端主要有三個線程:

  1. main_ui 線程:負責 UI 渲染

  2. mqt_js 線程:負責執(zhí)行 JS 代碼

  3. mqt_native_modules 線程:與 NativeModule 相關(guān)

每個線程都有與其綁定的消息隊列。native 側(cè) (main_ui 和 mqt_native_modules 線程) 通過調(diào)用 jniCallJSFunction 和 jniCallJSCallback 方法來執(zhí)行 JS 側(cè)的代碼,從而實現(xiàn)與 mqt_js 線程交互;mqt_js 線程通過調(diào)用 NativeModule 暴露給 JS 側(cè)的方法與 mqt_native_modules 線程交互;而 main_ui 與 mqt_native_modules 可通過 Handler 直接交互[51]。

React Native 的虛擬 DOM 機制

React Native 使用虛擬 DOM 來提高渲染效率,這與 React 在 Web 上的實現(xiàn)類似。

虛擬 DOM 的概念

虛擬 DOM 是一個輕量級的 JavaScript 對象,表示 DOM 樹的結(jié)構(gòu)。它具有平臺無關(guān)性:它描述的 UI 控件只是數(shù)據(jù)結(jié)構(gòu)層的,具體渲染工作是交給了原生渲染引擎(瀏覽器、iOS、Android)去處理[46]。

React Native 中的虛擬 DOM

在 React Native 里面,用來表示 dom 屬性的對象有以下關(guān)鍵屬性:

javascript

復(fù)制

解釋
var ele = {
  ... type: type, // 元素的類型 key: key, // 元素key標示 ref: ref, // 元素的引用 props: props, // 元素的參數(shù),包含children 
  ... 
}

React 里面的虛擬 DOM 把真實 DOM 分為了以下幾種類型:

  • 原子類型:類型為字符串,結(jié)構(gòu)上不可再分解,渲染由平臺底層支持。

  • 組合類型:類型為函數(shù)構(gòu)造器,它給我們提供了一種自定義元素 UI 和行為的能力。

渲染過程

React Native 的渲染過程大致如下:

  1. 將虛擬 DOM 轉(zhuǎn)換為平臺特定的原生控件

  2. 通過 UI Manager 創(chuàng)建和更新原生控件

  3. 利用 Yoga 布局引擎進行布局計算

  4. 將計算結(jié)果傳遞給原生層進行實際渲染

在 React Native 里面,是通過 UI Manager 來創(chuàng)建視圖的,基于 Virtual DOM,React Native 把不同平臺創(chuàng)建視圖的邏輯封裝了一層,不同平臺通過 Bridge 調(diào)用 UI Manager 來創(chuàng)建不同的 Native 視圖[46]。

React Native 的性能優(yōu)化

React Native 的性能優(yōu)化是開發(fā)者關(guān)注的重點,以下是幾個關(guān)鍵點:

跨語言通信的性能問題

性能是我們考量一個框架或一套技術(shù)方案的重要指標之一。相對于 Java、OC 等編程語言,一直以來 JS 都留給我們執(zhí)行慢的印象,其實隨著 JS 語言的發(fā)展以及 JS 引擎的不斷優(yōu)化,現(xiàn)代 JS 代碼的執(zhí)行速度已經(jīng)非??炝?。

性能問題一般不會出現(xiàn)在 JS 域和 native 域,而往往會出現(xiàn)在 C++ Bridge 上。這是因為跨語言通信需要進行數(shù)據(jù)的序列化與反序列化,而這個過程是非常耗時的[51]。

UI 的異步更新

React Native 中的 UI 更新是異步完成的。JS 側(cè)的更新指令被批量、異步地發(fā)送到 native 側(cè),在 native 執(zhí)行實際的更新操作時,JS 線程不會被阻塞。React 為了解決 Web 上的類似問題,提出了虛擬 DOM 的概念,結(jié)合一個智能的 diff 算法,將我們在 JS 側(cè)對組件的更改批量、異步地發(fā)送到 native 側(cè)–同時頁最小化了需要通過 Bridge 傳遞的數(shù)據(jù)量(diff 算法)[51]。

Hermes 引擎

Hermes 是 Facebook 在 2019 年發(fā)布的新一代 JS Engine,Hermes 是一款小巧輕便的 JavaScript 引擎,專門針對在 Android 上運行 React Native 進行了優(yōu)化:應(yīng)用啟動時間減少、減少內(nèi)存使用量并縮小應(yīng)用程序大小,此外因為它采用 JavaScript 標準實現(xiàn),所以很容易在 React Native 應(yīng)用中集成[46]。

React Native 的組件系統(tǒng)

React Native 的組件系統(tǒng)是其核心功能之一,理解組件如何創(chuàng)建和渲染對于掌握 React Native 至關(guān)重要。

元組件與復(fù)合組件

從一定角度上來說,React 的組件可以分為兩種:

  1. 元組件:框架內(nèi)置的,可以直接用的組件。在 RN 上可以理解為就是 View/Image 這種。不同平臺有不同的元組件實現(xiàn)。

  2. 復(fù)合組件:用戶封裝之后的組件,一般可以通過 React.createClass 來構(gòu)建,提供 render() 方法返回渲染目標(ES6 中可以繼承 React.Component)。

在 React 核心庫中提供了 instantiateReactComponent.js,供渲染平臺調(diào)用。它在碰見 ReactElement 時會根據(jù)其中的 type 生成元組件或者復(fù)合組件,邏輯如下[50]:

  1. 當對象的 type 如果是 string 或 function 時走第一層邏輯。當 type 為 string 時,渲染平臺可以通過 ReactHostComponent.injectGenericNameClass 這個 API 來注入生成組件邏輯;若 type 函數(shù)的原型鏈中具有元組件 API 時,則 new 一個 type 實例;否則就生成一個 ReactCompositeComponent(即復(fù)合組件)。

  2. 當對象為 string 時(此種情況對應(yīng)直接寫 string,而不是用 jsx 包裹起來的語法),也交由渲染平臺處理,可以通過 ReactHostComponent.injectTextComponentClass 來注入組件生成邏輯;

  3. 以上都不符合,則報錯。

元組件的實現(xiàn)

React Native 的元組件通常是一個復(fù)合組件,但是它的 render 方法返回的是一個元組件。例如,View 組件的代碼在 Libraries/Components/View/View.js 下,其實是一個復(fù)合組件,但是它的 render 方法返回的是一個元組件:

javascript

復(fù)制

解釋
// View.jsconst View = React.createClass({// 屬性聲明...render: function() {return <RCTView {...this.props} />;
  },
});

const RCTView = requireNativeComponent('RCTView',View,
  {nativeOnly: {nativeBackgroundAndroid: true,nativeForegroundAndroid: true,
    },
  }
);

requireNativeComponent 做的事情是獲取 UI Manager 中的對應(yīng) ViewModule 配置,并創(chuàng)建一個 ReactNativeBaseComponent 的構(gòu)造函數(shù)[50]。

React Native 的新架構(gòu)

React Native 在不斷發(fā)展,其新架構(gòu)帶來了性能和開發(fā)體驗的顯著提升。

JSI(JavaScript Interface)

在 RN 中,JSI 是 JavaScript Interface 的縮寫,JSI 是一個輕量級的通用的 API 框架,可以應(yīng)用于任意的 JavaScript virtual machine,讓各種平臺可以方便地使用不同的 JavaScript 解析引擎(JavaScript virtual machine 包含 JavaScript Engine)。

JSI 是用 C++ 寫的,用于取代原先的 bridge,提高通信效率,已在 RN 的 0.58 中實現(xiàn)。有了 JSI,我們就能輕松地直接調(diào)用原生 UI Views 或 Native Modules 用 Java/ObjC 實現(xiàn)的方法(類似 RPC),而不是像原來那樣用一層 bridge 來排隊等待原生層返回的消息[46]。

新架構(gòu)的優(yōu)勢

JSI 本身不是 React Native 的一部分——它是一個統(tǒng)一的、輕量的、通用適用于任何(理論上)JavaScript 虛擬機的接口層。當把 JSI 加入到新架構(gòu)中后,它使得一些真正重要的改進成為可能:

  1. 第一個改進很直觀——javaScriptCore 現(xiàn)在可以更容易地被替換成其它引擎,其它選項包括微軟的 ChakraCore 和谷歌的 V8。

  2. 第二個改進,可以說是整個新架構(gòu)的基石,是通過使用 JSI,JavaScript 可以持有對 C++ 宿主對象的引用,并且對它進行調(diào)用。這意味著:JavaScript 和 Native 之間真正地相互知曉,并且不再需要通過 JSON 序列化傳遞消息,這會消除 Bridge 的阻塞問題[46]。

React Native 的熱更新機制

熱更新是 React Native 的一個關(guān)鍵特性,它允許開發(fā)者在不重新發(fā)布應(yīng)用的情況下更新應(yīng)用的功能。

熱更新原理

React Native 的產(chǎn)物 bundle 文件,本質(zhì)上是 JS 邏輯代碼加上 React Native 的 Runtime 的集合,所以在應(yīng)用一啟動的時候就會去獲取 bundle 文件,之后解析 bundle 文件,最后再由 JS Engine 去執(zhí)行具體的業(yè)務(wù)代碼邏輯。這就可以允許開發(fā)者在云端去更新 bundle 文件,然后應(yīng)用啟動的時候獲取最新的 bundle 文件,這一整個流程下來就實現(xiàn)了熱更新[46]。

增量更新(拆包)

對于 React Native 的代碼打包之后只會生成一個 Bundle 文件,這里面包含了基礎(chǔ)業(yè)務(wù)邏輯、React Native 的基礎(chǔ)庫類,所以我們可以把一個包拆分成:一個基礎(chǔ)包+ n 個業(yè)務(wù)包,其中基礎(chǔ)包是不變的,這就是 runtime,業(yè)務(wù)包就是具體的業(yè)務(wù),后面如果有更新,也只需要再打出一個業(yè)務(wù)包就行[46]。

React Native 與 Flutter 的比較

React Native 和 Flutter 都是用于跨平臺開發(fā)的框架,但它們在實現(xiàn)方式和使用體驗上有顯著差異。

開發(fā)體驗比較

React Native 在界面開發(fā)延續(xù)了 React 開發(fā)風(fēng)格,支持 css-in-js(其實就是用 js 來寫 css),而且在 0.59 版本之后支持了 React Hook 函數(shù)式編程,開發(fā)的時候大多只關(guān)心樣式界面的搭建,原生能力有客戶端或者 Bridge 實現(xiàn)。

Flutter 最大的特點在于:Flutter 是一套平臺無關(guān)的 UI 框架,并且在 Flutter 里面萬物皆 Widget。很多時候開發(fā)一個控件需要嵌套多個 Widget 去實現(xiàn),與 JS 里面的回調(diào)地獄有點像,而這也是被吐槽代碼嵌套樣式難看的原因[46]。

狀態(tài)管理比較

React Native 和 Flutter 對于狀態(tài)管理,兩者有著很高的相似度,雖然內(nèi)部實現(xiàn)有很大差別,但是都可以獲取 state 和 setState 的方式去更新頁面的狀態(tài)。

產(chǎn)物比較

React Native 產(chǎn)生的是 bundle 文件,實際上就是 JS 腳本文件;而 Flutter 編譯后 Android 產(chǎn)生的主要是一些應(yīng)用程序指令段、數(shù)據(jù)段,虛擬機數(shù)據(jù)段、指令段,iOS 則是 App.framework,其實也是一些原生的數(shù)據(jù)集。

原生能力與性能比較

其實兩者的在這方面的區(qū)別不是很大,性能方面 React Native 稍微差一點。但是在原生靈活性上 React Native 要有優(yōu)勢[46]。

結(jié)論

React Native 作為一種跨平臺開發(fā)框架,通過其獨特的三層架構(gòu)設(shè)計(JS層、Shadow層、Native層)和高效的通信機制,實現(xiàn)了"一次學(xué)習(xí),隨處編寫"的開發(fā)理念。其虛擬 DOM 機制和異步更新策略大大提高了渲染效率,而熱更新功能則為應(yīng)用迭代提供了便利。

隨著 React Native 不斷發(fā)展,其新架構(gòu)引入的 JSI 技術(shù)進一步優(yōu)化了跨語言通信效率,使 JavaScript 和 Native 之間能夠更直接地交互,消除了 Bridge 的阻塞問題。同時,React Native 與 Flutter 等其他跨平臺框架的比較顯示,React Native 在開發(fā)體驗和原生靈活性方面具有獨特優(yōu)勢。

理解 React Native 的底層原理和實現(xiàn)流程,對于開發(fā)者優(yōu)化應(yīng)用性能、解決開發(fā)問題、甚至參與框架改進都具有重要意義。通過本報告的深入分析,我們希望讀者能夠?qū)?React Native 的工作原理有更全面的了解,從而在實際開發(fā)中更加得心應(yīng)手。

參考資料

[11] React Native 架構(gòu)詳解. https://buhe.gitbooks.io/react-native-primer-pro/content/rn_arch/1.html.

[36] React Native Android 源碼框架淺析(主流程及 Java 與 JS 雙邊通信). https://blog.csdn.net/yanbober/article/details/53157456.

[46] React Native 原理與實踐. https://zhuanlan.zhihu.com/p/343519887.

[49] 我對 React 實現(xiàn)原理的理解. https://zhuanlan.zhihu.com/p/538096803.

[50] React Native 核心渲染流程分析(1) - 初識組件系統(tǒng). https://zhuanlan.zhihu.com/p/24834341.

[51] ReactNative設(shè)計與實現(xiàn)之三:整體架構(gòu). https://zhuanlan.zhihu.com/p/45836822.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容