【React Native】從原始碼一步一步解析它的實現原理
前言
花了半個多月,把React Native原始碼看了一遍,大概的實現邏輯全看明白了,希望對想了解React Native實現原理的同學有所幫助,其實只要看懂文章的四幅圖就明白它的原理了。
一、React Native背景
-
有沒有朋友想過一個問題,為什麼取名React Native?React是什麼,Native又是什麼?
React
-
React 是由Facebook推出的一個JavaScript框架,主要用於前段開發。
-
React 採用元件化方式簡化Web開發
DOM:每個HTML介面可以看做一個DOM
原生的web開發方式,HTML一個檔案,javaScript一個檔案,檔案分開,就會導致修改起來比較麻煩。
可以把一組相關的HTML標籤和JavaScript單獨封裝到一個元件類中,便於複用,方便開發。
-
React 可以高效的繪製介面
原生的Web,重新整理介面(DOM),需要把整個介面重新整理.
React只會重新整理部分介面,不會整個介面重新整理。
因為React獨創了Virtual DOM機制。Virtual DOM是一個存在於記憶體中的JavaScript物件,它與DOM是一一對應的關係,當介面傳送變化時,React會利用DOM Diff演算法,把有變化的DOM進行重新整理.
-
React是採用JSX語法,一種JS語法糖,方便快速開發。
Native
-
想要了解Native是什麼,需要了解下開發App有哪些開發模式,賣了一個館子,請繼續往下看。
二、常見的五種App開發模式
-
常見的開發模式有5種(Native App,Web App,Hybrid App,Weex,React Native)
Native App
-
Native App:指使用原生API開發App,比如iOS用OC語言開發
-
優點:效能高
-
缺點:開發維護成本高,養一個原生開發工程師需要很多錢,最重要iOS版本更新也成問題。
Web App
-
Web App:指使用Html開發的移動端網頁App,類似微信小程式,整個App都是網頁。
-
優點:使用者不需要安裝,不會佔用手機記憶體
-
缺點:使用者體驗不好,不能離線,必須聯網
Hybrid App
-
Hybrid App:混合開發模式,原生Api+Html共同開發,比如iOS,用html寫好介面,用UIWebView展示。
-
優點:介面複用性強,一個介面,iOS和安卓都可以使用
-
缺點:相對於原生,效能相對有所損害
Weex
-
Weex:基於Vue(JS框架)的語法開發的App,底層會自動把JS程式碼解析成對應平臺(iOS,安卓)的原生API,本質還是原生API開發,只不過表面是用Vue開發。
-
優點:可以做到一套程式碼,跨平臺執行,底層會自動判斷當前是哪個平臺,轉換為對應平臺的原生API程式碼。
-
缺點:開源較晚,網際網路上相關資料還比較少,社群規模較小
React Native
-
React Native:基於React開發的App
-
優點:跳過App Store稽核,遠端更新程式碼,提高迭代頻率和效率,既有Native的體驗,又保留React的開發效率。
-
缺點:對於不熟悉前端開發的人員上手比較慢,不能真正意義上做到跨平臺,使用後,對app體積增加。
-
相信大多數人瞭解完React Native,越來越困惑了,那不是跟Native衝突了嗎,Native是用原生Api開發,但是React Native又是用React開發。
-
要想徹底搞明白,需要了解React Native底層實現原理,又來了,想知道原理,繼續往下看
三、React Native原理
-
React Native原理其實跟Weex差不多,底層也會把React轉換為原生API
-
React Native和Weex區別在於跨平臺上面,Weex只要寫一套程式碼,React Native需要iOS,安卓都寫,說明React Native底層解析原生API是分開實現的,iOS一套,安卓一套。
四、React Native如何把React轉化為原生API
-
React Native會在一開始生成OC模組表,然後把這個模組表傳入JS中,JS參照模組表,就能間接呼叫OC的程式碼。
相當於買了一個機器人(OC),對應一份說明書(模組表),使用者(JS)參照說明書去執行機器人的操作。
五、React Native是如何做到JS和OC互動
-
iOS原生API有個JavaScriptCore框架,通過它就能實現JS和OC互動,想了解JavaScriptCore,請點選JavaScriptCore
1.首先寫好JSX程式碼(React框架就是使用JSX語法)
2.把JSX程式碼解析成javaScript程式碼
3.OC讀取JS檔案
4.把javaScript程式碼讀取出來,利用JavaScriptCore執行
5.javaScript程式碼返回一個陣列,陣列中會描述OC物件,OC物件的屬性,OC物件所需要執行的方法,這樣就能讓這個物件設定屬性,並且呼叫方法。
JS和OC互動.png
六、React Native啟動流程(iOS)
-
1.建立RCTRootView -> 設定視窗根控制器的View,把RN的View新增到視窗上顯示。
-
2.建立RCTBridge -> 橋接物件,管理JS和OC互動,做中轉左右。
-
3.建立RCTBatchedBridge -> 批量橋架物件,JS和OC互動具體實現都在這個類中。
-
4.執行[RCTBatchedBridge loadSource] -> 載入JS原始碼
-
5.執行[RCTBatchedBridge initModulesWithDispatchGroup] -> 建立OC模組表
-
6.執行[RCTJSCExecutor injectJSONText] -> 往JS中插入OC模組表
-
7.執行完JS程式碼,回撥OC,呼叫OC中的元件
-
8.完成UI渲染
React Native啟動流程(iOS).png
七、React Native載入JS原始碼流程(iOS)
-
1.[RCTJavaScriptLoader loadBundleAtURL] -> 載入遠端伺服器中JS程式碼
-
2.attemptAsynchronousLoadOfBundleAtURL(C函式) -> 開啟非同步載入JS程式碼
-
3.[RCTBatchedBridge executeSourceCode:sourceCode] -> 讓批量交接物件執行原始碼
-
[RCTJSCExecutor executeApplicationScript] -> 交給JS執行者(RCTJSCExecutor)執行原始碼)
-
真正執行JS程式碼的是RCTJSCExecutor物件
-
5.[postNotificationName:RCTJavaScriptDidLoadNotification] -> 傳送JS程式碼執行完成通知
-
6.RCTRootView監聽到RCTJavaScriptDidLoadNotification通知
-
7.建立RCTRootContentView
-
8.獲取RCTBridge中的RCTUIManager註冊RCTRootView,並且記錄RCTRootView,_viewRegistry
RCTUIManager:管理UI元件
_viewRegistry:儲存所有註冊的View
-
9.[RCTRootView runApplication:bridge] -> 通知JS執行App
-
10.[RCTBridge enqueueJSCall:@"AppRegistry"
1
2
3
|
method:@ "runApplication" args:@[moduleName, appParameters] completion:NULL] -> 通過橋接物件讓JS呼叫AppRegistry |
-
11.[RCTBatchedBridge _actuallyInvokeAndProcessModule:module method:method arguments:args queue:RCTJSThread] -> 通過批量橋架讓JS執行AppRegistry方法
-
12.[RCTJSCExecutor _executeJSCall:bridgeMethod arguments:@[module, method, args] unwrapResult:unwrapResult callback:onComplete] -> 讓JS執行者呼叫JS程式碼
-
13.執行完JS程式碼,就能獲取執行JS結果,是一個陣列,OC需要做的事情都會儲存到這個陣列中
-
14.[RCTBatchedBridge _processResponse:json error:error] -> 處理執行完JS程式碼返回的結果物件
-
15.[RCTBatchedBridge handleBuffer] -> 處理JS返回的資料,JS會返回的方法呼叫陣列:按順序描述需要呼叫哪個物件的方法,一組呼叫包含(module,method,arguments)
-
16.[self callNativeModule:[moduleIDs[index] integerValue]
1
2
|
method:[methodIDs[index] integerValue] params:paramsArrays[index]] -> 遍歷陣列,依次執行原生方法 |
注意:當前方法,在遍歷陣列中的程式碼塊中執行,不只是執行一次.
React Native載入JS原始碼流程.png
八、React NativeUI控制元件渲染流程(iOS)
-
1.[RCTRootView runApplication:bridge] -> 通知JS執行App
-
2.[RCTBatchedBridge _processResponse:json error:error] -> 處理執行完JS程式碼(runApplication)返回的相應,包含需要新增多少子控制元件的資訊。
-
3.[RCTBatchedBridge batchDidComplete] -> 批量橋架物件呼叫批量處理完成方法
-
4.[RCTUIManager batchDidComplete] -> RCTUIManager呼叫批量處理完成的方法,就會開始去載入rootView的子控制元件。
-
5.[RCTUIManager createView:viewName:rootTag:props] -> 通過JS執行OC程式碼,讓UI管理者建立子控制元件View
通過RCT_EXPORT_METHOD巨集定義createView這個方法
1
2
3
4
|
RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTag viewName:(NSString *)viewName rootTag:(__unused NSNumber *)rootTag props:(NSDictionary *)props) |
RCT_EXPORT_METHOD巨集:會在JS中生成對應的OC方法,這樣JS就能直接呼叫
-
注意每建立一個UIView,就會建立一個RCTShadowView,與UIView一一對應
-
RCTShadowView:儲存對應UIView的佈局和子控制元件,管理UIView的載入
-
6.[RCTUIManager _layoutAndMount] -> 佈局RCTRootView和增加子控制元件
-
7.[RCTUIManager setChildren:reactTags:] -> 給RCTRootView對應的RCTRootShadowView設定子控制元件
注意:此方法也是JS呼叫OC方法
-
8.[RCTRootShadowView insertReactSubview:view atIndex:index++] -> 遍歷子控制元件陣列,給RCTRootShadowView插入所有子控制元件
-
9.[RCTShadowView processUpdatedProperties:parentProperties:] -> 處理儲存在RCTShadowView中屬性,就會去佈局RCTShadowView對應UIView的所有子控制元件
-
10.[RCTView didUpdateReactSubviews] -> 給原生View新增子控制元件
-
11.完成UI渲染
React Native (UI控制元件渲染流程).png
九、React Native事件處理流程(iOS)
-
1.在建立RCTRootContentView的時候,內部會建立RCTTouchHandler
RCTTouchHandler:繼承UIGestureRecognizer,也就是它就是一個手勢
它會作為RCTRootContentView的手勢,這樣點選RCTRootContentView,就會觸發RCTTouchHandler
RCTTouchHandler:內部實現了touchBegin等觸控方法,用來處理觸控事件
-
2.在建立RCTTouchHandler的時候,內部會建立RCTEventDispatcher
RCTEventDispatcher:用來把事件處理傳遞給JS的方法處理,也就是當UI介面產生事件,就會執行JS的程式碼處理。
-
3.通過RCTRootContentView截獲點選事件
產生事件就會去觸犯RCTRootContentView中的RCTTouchHandler物件。
-
4.當產生事件的時候,會執行[RCTTouchHandler touchBegin]
-
5.RCTTouchHandler的touch方法,會執行[RCTTouchHandler _updateAndDispatchTouches:eventName:]
內部會建立RCTTouchEvent事件物件
-
6.[RCTEventDispatcher sendEvent:event] -> 讓事件分發物件呼叫傳送事件物件
內部會把事件儲存到_eventQueue(事件佇列中)
-
7.[RCTEventDispatcher flushEventsQueue] -> 讓事件分發物件沖刷事件佇列,就是獲取事件佇列中所有事件執行
-
8.[RCTEventDispatcher dispatchEvent:event] -> 遍歷事件佇列,一個一個分發事件
分發事件的本質:就是去執行JS的程式碼,相應事件。
-
9.[RCTBatchedBridge enqueueJSCall:[[event class] moduleDotMethod] args:[event arguments]]; -> 讓橋架物件呼叫JS處理事件
本質:就是產生事件呼叫JS程式碼
-
10.這樣就能完成把UI事件交給JS程式碼相應
React Native (事件處理流程).png
相關文章
- HashMap實現原理一步一步分析(1-put方法原始碼整體過程)HashMap原始碼
- 【原始碼解析】React Native元件渲染原始碼React Native元件
- 5000字的React-native原始碼解析React原始碼
- 通過React Fiber本身的測試用例,一步一步除錯它的原始碼,直觀感受下它的執行機制React除錯原始碼
- promise原理—一步一步實現一個promisePromise
- 一步步解析jQuery原始碼jQuery原始碼
- React Native 0.55.4 Android 原始碼分析(Java層原始碼解析)React NativeAndroid原始碼Java
- React Native通訊原理原始碼分析一React Native原始碼
- React Native通訊原理原始碼分析二React Native原始碼
- 一步一步分析Redux原始碼?Redux原始碼
- Java集合類,從原始碼解析底層實現原理Java原始碼
- 一步一步實現直播軟體原始碼的RTMP推流流媒體服務原始碼
- 深入原始碼解析 tapable 實現原理原始碼
- Netty原始碼解析 -- PoolChunk實現原理Netty原始碼
- Netty原始碼解析 -- PoolSubpage實現原理Netty原始碼
- 一步一步,實現自己的ButterKnife(二)
- 從零開始學React:四檔(下篇)一步一步學會react-reduxReactRedux
- InnoDB MVCC實現原理及原始碼解析MVC原始碼
- 一步一步實現一個PromisePromise
- 一步一步實現手寫PromisePromise
- Vue雙向繫結原理,教你一步一步實現雙向繫結Vue
- 我們來一步一步分析koa2的原始碼?原始碼
- 一步一步理解Generator函式的原理函式
- 一步一步實現單身狗雨
- 從原始碼解讀Category實現原理原始碼Go
- 深度解析Spring Cloud Ribbon的實現原始碼及原理SpringCloud原始碼
- 一步一步帶你瞭解EventBus3.1.1 原始碼S3原始碼
- 一步一步實現 .NET 8 部署到 DockerDocker
- 一步一步實現Vue資料繫結Vue
- Java 從 Map 到 HashMap 的一步步實現JavaHashMap
- 從零開始學React:四檔(上)一步一步學會react-redux (自己寫個Redux)ReactRedux
- React Native BackHandler exitApp 原始碼分析React NativeAPP原始碼
- Dubbo 實現原理與原始碼解析系列 —— 精品合集原始碼
- 通過原始碼一步一步分析 ArrayList 擴容機制原始碼
- 一步一步實現一個Promise A+規範的 PromisePromise
- React原始碼解析React原始碼
- 從ReentrantLock詳解AQS原理原始碼解析ReentrantLockAQS原始碼
- 一步一步帶你封裝基於react的modal元件封裝React元件
- 一步一步實現一個符合Promises/A+規範的PromisePromise