1、Virtual DOM
狀态改變了要操作相應的 DOM 元素,為什麼不做一個東西可以讓視圖和狀态進行
綁定?讓狀态變更視圖自動跟着變更,就不用手動更新頁面了。這就是後來的 MVVM
模式,隻要在模版中聲明視圖元件是和什麼狀态進行綁定的,雙向綁定引擎就會在狀态
更新的時候自動更新視圖,MVVM 可以能很好的降低維護狀态以及減少視圖的複雜程度。
一旦狀
态發生了變化,就用模版引擎重新渲染整個視圖,然後用新的視圖更換掉舊的視圖。
當使用者點選的時,還是在 JS 裡面更新狀态,但是頁面更新就不用手動
操作 DOM 了,直接把整個表格用模版引擎重新渲染一遍,然後設定一下 innerHTML 。
那麼這個方法會有個很大的問題,會導緻 DOM 操作變慢,因為任何的狀态變更都要重
新構造整個 DOM,成本效益很低。對于局部的小視圖的更新,這樣沒有問題(backbone
就是這麼幹的)。但對于大型視圖,需要更新頁面較多局部視圖時,這樣的做法就非常不
可取。
DOM 很慢,一旦浏覽器接收到一個 HTML 檔案,渲染引擎 Render Engine
就開始解析它,根據 HTML 元素 Elements 對應地生成 DOM 節點 Nodes,最終組成一
棵 DOM 樹。
構造了渲染樹以後,浏覽器引擎開始着手布局 Layout。布局時,渲染樹上的每個節點根據
其在螢幕上應該出現的精确位置,配置設定一組螢幕坐标值。接着,浏覽器将會通過周遊渲染樹,
調用每個節點的 Paint 方法來繪制這些 Render 對象。Paint 方法根據浏覽器平台,使用不
同的 UI後端 API(Agnostic UI Backend API)通過繪制,最終将在螢幕上展示内容。隻要
在這過程中進行一次 DOM 更新,整個渲染流程都會重做一遍。
DOM 我們都可以用 JavaScript 對象來表示。那反過來,就可以用 JavaScript 對象表示的樹結
構來建構一個真正的 DOM 。當狀态變更時,重新渲染這個 JavaScript 的對象結構,實作視圖
的變更,結構根據變更的地方重新渲染。
這就是所謂的 Virtual DOM 算法:
用 JavaScript 對象結構表示 DOM 樹的結構;然後用這個樹建構一個真正的 DOM 樹,插到文
檔當中當狀态變更時,重新構造一棵新的對象樹。然後用新的樹和舊的樹進行比較兩個數的差異。
然後把差異更新到久的樹上,整個視圖就更新了。Virtual DOM 本質就是在 JS 和 DOM 之間做
了一個緩存。既然已經知道 DOM 慢,就在 JS 和 DOM 之間加個緩存。JS 先操作 Virtual DOM
對比排序/變更,最後再把整個變更寫入真實 DOM。
https://www.cnblogs.com/wubaiqing/p/6726429.html
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文法糖,友善快速開發。
作者:袁峥
連結:https://www.jianshu.com/p/5cc61ec04b39
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
對于 Android 開發者來說, RN是一個普通的安卓程式加上一堆事件響應, 事件來源主要是JS的指令。主要有二個線程,UI main thread, JS thread。 UI thread建立一個APP的事件循環後,就挂在looper等待事件 , 事件驅動各自的對象執行指令。 JS thread 運作的腳本相當于底層資料采集器, 不斷上傳資料,轉化成UI 事件, 通過bridge轉發到UI thread, 進而改變真實的View。 後面再深一層發現, UI main thread 跟 JS thread更像是CS 模型,JS thread更像服務端, UI main thread是用戶端, UI main thread 不斷詢問JS thread并且請求資料,如果資料有變,則更新UI界面。
JS 也是單線程事件循環
JAVA層會把JS 關心的事件通過bridge直接使用javascriptCore的接口執行固定的腳本, 比如"requrire (test_module).test_methode(test_args)"。此時,UI main thread相當于work thread, 把系統事件或者使用者事件往JS層抛,同時,JS 層也不斷調用子產品API或者UI元件 , 驅動JAVA層完成實際的View渲染。JS開發者隻需要監聽JS層framework定義的事件即可。
https://blog.csdn.net/xiangzhihong8/article/details/52623852
四、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對象所需要執行的方法,這樣就能讓這個對象設定屬性,并且調用方法。
六、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加載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
-
:管理UI元件RCTUIManager
- _viewRegistry:儲存所有注冊的View
-
- 9.[RCTRootView runApplication:bridge] -> 通知JS運作App
-
10.[RCTBridge enqueueJSCall:@"AppRegistry"
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]
method:[methodIDs[index] integerValue]
params:paramsArrays[index]] -> 周遊數組,依次執行原生方法
- 注意:目前方法,在周遊數組中的代碼塊中執行,不隻是執行一次.
八、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
- 通過
定義createView這個方法RCT_EXPORT_METHOD宏
RCT_EXPORT_METHOD(createView:(nonnull NSNumber *)reactTag viewName:(NSString *)viewName rootTag:(__unused NSNumber *)rootTag props:(NSDictionary *)props)
-
:會在JS中生成對應的OC方法,這樣JS就能直接調用RCT_EXPORT_METHOD宏
- 注意每建立一個UIView,就會建立一個RCTShadowView,與UIView一一對應
-
:儲存對應UIView的布局和子控件,管理UIView的加載RCTShadowView
- 通過
- 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事件處理流程(iOS)
- 1.在建立RCTRootContentView的時候,内部會建立RCTTouchHandler
-
:繼承UIGestureRecognizer,也就是它就是一個手勢RCTTouchHandler
- 并且它會作為RCTRootContentView的手勢,這樣點選RCTRootContentView,就會觸發RCTTouchHandler
-
:内部實作了touchBegin等觸摸方法,用來處理觸摸事件RCTTouchHandler
-
- 2.在建立RCTTouchHandler的時候,内部會建立RCTEventDispatcher
-
:用來把事件處理傳遞給JS的方法處理,也就是當UI界面産生事件,就會執行JS的代碼處理。RCTEventDispatcher
-
- 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代碼相應

作者:袁峥
連結:https://www.jianshu.com/p/5cc61ec04b39
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
React Native Android 源碼架構淺析(主流程及 Java 與 JS 雙邊通信)
https://blog.csdn.net/yanbober/article/details/53157456