RN 與native 的交互javascript
0>>> React 的渲染機制php
1>>> react-native 渲染原理 前端
2>>> react-native 如何與原生通訊java
3>>> 如何封裝一個原生視圖組件node
4>>> react-native 的線程管理react
RN的本質是利用 js 調用 native 端的組件, 從而實現相應的功能android
// react ios
React 與 React native 的原理是相同的,都是由 javascript 實現的虛擬DOM 來驅動界面 View 的渲染,只不過 React.js 驅動 HTML DOM 的渲染, RN 是驅動 ios/android 原生組件的渲染git
都知道 React native 是虛擬 DOM 機制,是存在於內存中的 JavaScript 對象對應着真實的 DOM 節點,操做DOM 很慢,但操做JavaScript 很快,因爲採用diff算法只渲染相比以前改變的部分並非所有渲染,因此更快, setState 時至關於建立了一個影子 DOM 而後比較新舊兩個 DOM 的區別觸發 render 函數,從新渲染須要改變部分的DOM節點github
React 是 fb 推出的一個 js前端框架, 採用組件化方式簡化了 web 開發
(1)DOM : 每一個 HTML 頁面能夠當作一個 DOM 能夠把 HTML標籤和 js 單獨封裝到一個組件類中,便於複用,方便開發
(2)更高效 原生的 web 刷新 DOM, 須要刷新整個頁面 react 只刷新部分頁面
(3) 首創了 Virtual DOM 機制, 是一個存在於內存中的 js對象,之因此很是快是由於他從不直接操做 DOM, 它和 DOM 是一一對應的關係, 當頁面發生變化時, react 會利用 DOM diff 算法, 把有變化的 DOM 進行刷新
由當前狀態決定 UI 界面 狀態發生變化時 由 diff算法決定刷新哪些 DOM 節點, 虛擬DOM是在DOM的基礎上創建了一個抽象層,對數據和狀態所作的任何改動,都會被自動且高效的同步到虛擬DOM,最後再批量同步到DOM中。
在React中,render執行的結果獲得的並非真正的DOM節點,而僅僅是JavaScript對象,稱之爲虛擬DOM
逐層進行節點比較 若是上面的同級節點不一樣,該節點及其子節點會被徹底刪除掉,不會進行進一步的遞歸比較,這樣只須要對 DOM 樹進行一次遍歷 ,便能完成整個DOM 樹的比較
DOM 結構的轉換
好比這種正常的邏輯: A.parent.remove(A) D.append(A)
對於 React 只考慮同層的節點的位置變換 不一樣層的只有簡單的建立和刪除, 當發現節點中 A 不見了 ,直接銷燬 A 新建一個 A 節點做爲 D 的子節點
A.destroy() A = new A() A.append(new B()) A.append(new C()) D.append(A)
同級的列表節點的比較
如圖: 在 JQuery 中 $(B).after(F)直接插入一個節點就行了
在 React 只能告訴新的頁面是 ABFCDE組成.由 diff算法完成更新 他只能把 A 更新爲 A B 更新爲 B C 更新爲 F 這樣
若是給每一個節點一個惟一標識的 key, React 就能夠找到正確的位置去插入新的節點,這也是爲何項目中有些列表常常報警告缺乏 key, 也是潛在的性能問題, 雖然不影響運行
對於相同類型的元素, React 會先查看二者的屬性差別, 而後保留相同的底層 DOM 節點,僅僅去更新那些被修改的屬性好比只修改了 width color 等 處理完 根DOM節點後, 會根據上面的判斷邏輯對子節點進行遞歸掃描
須要注意的兩點:
1> 該算法不會去嘗試匹配那些不一樣組件類型的子元素樹。 若是你看到本身在返回類似輸出結果的兩個組件類型之間來來回回,你可能須要把它們改成相同的類型組件。
2> key屬性應該是穩定,可預測和惟一的。 不穩定的鍵(如使用Math.random()生的key)將致使許多組件實例和DOM節點進行沒必要要地重複建立,這可能致使子組件中的性能下降和state丟失。
React.render 渲染流程
1>>> React.render() 將咱們的 element 根虛擬節點渲染到 container 元素中
2>>> 根據 element 的類型不一樣, 分別實例化 ReactDOMTextComponnet ReactDOMComponent ReactCompositeComponent類, 這些類用來管理 ReactElement ,負責將不一樣的 ReactElement 轉化爲 DOM, 並更新 DOM
3>>> ReactCompositeComponent 實例調用 mountComponent 方法後內部調用render 方法, 返回了 DOM Elements
React 的更新機制
React Element 一個描述 DOM 節點或 component 實例的字面級對象, 它包含一些信息,組件的 type 和 props, 就像一個描述 DOM 節點的元素(虛擬節點), 能夠經過 React.creatElement 方法建立
reactClass 平時咱們所建立的 component 組件(類或函數) ReactClass 實例化後調用 render 函數可返回 DOMElement
調用 React.render 方法, 將 element根虛擬節點渲染到 container 元素中, 根據 element 的類型不一樣,分別實例化 ReactDOMTextComponent ReactDOMComponent ReactCompositeComponent 類, 這些類用來管理 ReactElement 負責將不一樣的 ReactElement 轉化爲 DOM 並更新 DOM , ReactCompositeComponent 實例調用 mountComponent 方法後內部調用 render 方法, 返回 DOMElement
總結: (1)節點之間的比較 節點 node .包括兩種類型 一個是 React 組件 一個是 HTML 的 DOM
節點類型不一樣: 直接使用新的替換舊的
類型相同: 樣式不一樣,修改樣式便可,在 React 裏樣式並非純粹的字符串也是一個對象,修改完當前節點以後,遞歸處理子節點
組件類型相同: 使用 React 機制處理,通常使用新的 props 替換舊的 props, 並在以後調用組件的 componentWill /DidRecieveProps 方法, 以前的組件的 render 方法會被調用\
(2)列表之間的比較
一列節點中有一個發生變化, React 並無什麼好的辦法處理,循環兩個列表,找出不一樣是惟一的處理方法
可是,下降這個算法的難度的辦法是在生成一個列表時給每個節點一個惟一的 key,就能夠方便的找出哪一個節點發生變化
// React component的生命週期函數
裝載組件
更新組件狀態
存在期主要是用來處理與用戶的交互,如:點擊事件,都比較簡單,也不是很經常使用,具體有如下幾個過程:
卸載(刪除)組件 銷燬期,用於清理一些無用的內容,如:點擊事件Listener 定時器的移除
上面函數的調用順序是:
建立時
更新時
//react-native 是如何作到js與 oc 交互的 JavascriptCore
React native 會在一開始生成兩個模塊配置表, js按照整個表就能夠找到須要調用的方法
iOS 是經過JavaScriptCore 與 oc交互
react naive 啓動流程
React -native 可以在 iOS 和安卓設備上運行起來, 是由於 rn 與 native 之間有一種交互. javascriptCore 引擎, js告訴 oc須要執行什麼, iOS 會本身去調用 UIKit 等框架繪製界面
1 建立 RCTRootView
2 建立 RCTBridge 橋接對象 管理 js與 oc的交互
3 建立 RCTBatchedBridge 批量橋接對象
4 執行 [RCTBatchedBridge loadSource] 加載 js 源碼
5 執行 [RCTBatchedBridge initModulesWithDispatchGroup] 建立模塊配置表
6 執行 [RCTJSExcutor injectJSONText] 往 js 中插入 OC 模塊表
7 執行完 js代碼 回調 OC 調用 OC 中的組件
8 完成渲染
RCTBridge 是負責雙方通訊的橋樑, 真正起做用的是RCTBatchedBridge類, 能夠看一下他都作了什麼?
當建立完模塊的實例對象以後,會將該實例保存到一個RCTModuleData對象中,RCTModuleData裏包含模塊的類名,名稱,方法列表,實例對象、該模塊代碼執行的隊列以及配置信息等,js層就是根據這個對象來查詢該模塊的相關信息。
// react-native 加載 js源碼流程
// react-native UI控件渲染流程
用戶能看到的一切內容都源於 RootView, 實際上在建立 RootView 以前, RN 先建立了一個 Bridge 對象. 他是 OC與 JS 交互的橋樑, 整個 RN 的初始化過程其實也就是在建立整個橋樑對象
初始化方法的核心是 setUp 方法, setUp 方法主要任務是建立BatchedBridge, BatchedBridge的做用是批量讀取 js對 OC 的方法調用,建立BatchedBridge的關鍵是 start 方法, 分爲5個步驟:
1>> 讀取 js源碼
2>> 初始化模塊信息
3>> 初始化 JS 代碼執行器 RCTJSCExecutor 對象
4>> 生產模塊列表並寫入 JS 端
5>> 執行 js 源碼 調用 OC
在調用 OC 以前, JS 會解析出方法的 MoudleID MethodID Argument 並放入 MessageQueue. 等待 OC 拿走,或者超時後主動發送給 OC
OC負責調用的方法是 handleBuffer, 他的參數是一個含有四個元素的數組, 每一個元素也是一個數組,分別存放 moudleID methodID params , 函數內部在每一次調用方法的時候調用_ handleRequestNumber: MoudleID: MethodID: params: 方法, 經過查找模塊配置表找出要調用的方法, 並經過 runtime 動態調用 [method invokeWithBridge:self moudle:moudleDate.instance arguments:params] processMethodSignature ,他會根據 js 的 callbackID 建立一個 block, 並在調用完函數以後執行這個 block
1. [RCTRootView runApplication] 通知 js 運行 APP
2. [RCTBatchedBridge _processResponse:json error:error] 處理執行完js 代碼返回的響應 , 包含須要添加多少個子控件的信息
3 . [RCTBatchedBridge batchDidComplete] 批量橋接對象調用批量處理完成方法
4 . [RCTUIManager batchDidComplete] RCTUIManager 調用批量處理完成的方法,就會開始去加載 rootView 的子控件
5 . [RCTUIManager creatView: viewName :rootTags: props:] 經過 js 執行 OC 代碼, 讓 UIManager 建立子控件 View
6 .[RCTUIManager _layoutAndMount] 佈局子組件
7 .[RCTUIManager setChildren: reactTags: ] 給 RCTRootView 對應的 RCTRootShadowView 設置子組件
8 .[RCTRootShadowView insertReactSubView:view atIndex:index++] 遍歷子組件數組, 給 RCTRootShadowView 插入全部子控件
9.[RCTShadowView processUpdatedProperties:parentProperties] 處理保存在 RCTShadowView中的屬性, 就會去佈局 RCTShadowView 對應 UIView的全部子控件
10.[RCTView didUpdateReactSubviews] 給原生 View 添加子控件 完成 UI 渲染
render 函數的翻譯
ReactElement.createElement = function (type, config, children){ ... }
UIManager 經過調用 createView 方法建立原生的 UIView
UIManager 經過 dispatchViewManagerCommand 來實現把原生UI 的方法給 JS 響應
UIManager 是一個 native moudle
這個模塊是NativeModule方式定義的,在RN的JS端啓動時,端上會經過JSC把收集到的模塊信息(名稱)打包到JS端全局變量global.__fbBatchedBridgeConfig中,並採用延遲加載策略:設置NativeModules.[模塊名]的getter,延遲經過JSC讀取模塊詳細信息(方法、命令號等信息)。在調用的時候會放到MessageQueue的隊列裏,批量提交,兩次批量提交限制的最小間隔爲5ms。
RN和原生同樣,也是先渲染內部子控件,而後再渲染外部控件。因此Component來自React的,可是UI控件是React-Native的,在render生命週期執行的時候會執行子控件的render方法,子控件會調用UIManager來把信息傳遞到原始的UIManagerModule,UIManagerModule根據傳過來的Tag找到對應的UIManager,最後生成一個Operation添加到UI處理隊列中,當mDispatchUIRunnables執行runable的時候調用Operation.execute抽象方法,其實就是調用UIManager.createViewInstance來真正生成View,而後調用viewManager.updateProperties 設置View的屬性。這樣一個控件就建立出來了
// react- native 的事件處理流程
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代碼響應
RN與原生(iOS)之間的通訊
OC端與 JS 端分別有一個Bridge, 兩個 Bridge 都保存了一樣一份模塊配置表, OC 要告訴 JS 本身有什麼模塊 , 模塊裏有什麼方法, JS 知道這些方法才能夠調用, JS 調用 OC 模塊方法的時候, 經過 Bridge 裏的配置表把模塊ID 方法 ID 和參數傳給 OC, OC 經過配置表找到對應的方法執行, 如圖
詳細流程:
1.JS端調用某個OC模塊暴露出來的方法。
2.把上一步的調用分解爲ModuleName,MethodName,arguments,再扔給MessageQueue處理。
在初始化時模塊配置表上的每個模塊都生成了對應的remoteModule對象,對象裏也生成了跟模塊配置表裏一一對應的方法,這些方法裏能夠拿到自身的模塊名,方法名,並對callback進行一些處理,再移交給MessageQueue。具體實如今BatchedBridgeFactory.js的_createBridgedModule裏,整個實現區區24行代碼,感覺下JS的魔力吧。
3.在這一步把JS的callback函數緩存在MessageQueue的一個成員變量裏,用CallbackID表明callback。在經過保存在MessageQueue的模塊配置表把上一步傳進來的ModuleName和MethodName轉爲ModuleID和MethodID。
4.把上述步驟獲得的ModuleID,MethodId,CallbackID和其餘參數argus傳給OC。至於具體是怎麼傳的,後面再說。
5.OC接收到消息,經過模塊配置表拿到對應的模塊和方法。
實際上模塊配置表已經通過處理了,跟JS同樣,在初始化時OC也對模塊配置表上的每個模塊生成了對應的實例並緩存起來,模塊上的每個方法也都生成了對應的RCTModuleMethod對象,這裏經過ModuleID和MethodID取到對應的Module實例和RCTModuleMethod實例進行調用。具體實如今_handleRequestNumber:moduleID:methodID:params:。
6.RCTModuleMethod對JS傳過來的每個參數進行處理。
RCTModuleMethod能夠拿到OC要調用的目標方法的每一個參數類型,處理JS類型到目標類型的轉換,全部JS傳過來的數字都是NSNumber,這裏會轉成對應的int/long/double等類型,更重要的是會爲block類型參數的生成一個block。
例如-(void)select:(int)index response:(RCTResponseSenderBlock)callback 這個方法,拿到兩個參數的類型爲int,block,JS傳過來的兩個參數類型是NSNumber,NSString(CallbackID),這時會把NSNumber轉爲int,NSString(CallbackID)轉爲一個block,block的內容是把回調的值和CallbackID傳回給JS。
這些參數組裝完畢後,經過NSInvocation動態調用相應的OC模塊方法。
7.OC模塊方法調用完,執行block回調。
8.調用到第6步說明的RCTModuleMethod生成的block。
9.block裏帶着CallbackID和block傳過來的參數去調JS裏MessageQueue的方法invokeCallbackAndReturnFlushedQueue。
10.MessageQueue經過CallbackID找到相應的JS callback方法。
11.調用callback方法,並把OC帶過來的參數一塊兒傳過去,完成回調。
整個流程就是這樣,簡單歸納下,差很少就是:JS函數調用轉ModuleID/MethodID -> callback轉CallbackID -> OC根據ID拿到方法 -> 處理參數 -> 調用OC方法 -> 回調CallbackID -> JS經過CallbackID拿到callback執行
說完原理,如今就是具體js怎麼調用 OC , OC 怎麼調用 JS
一 .JS調用 OC
1> 新建兩個OC 文件遵照 RCTBridgeMoudle協議,這裏以集成 native 的微博分享給 RN 調用爲例
2> 經過 RCT_EXPORT_MOUDLE()暴露當前模塊 RCT_EXPORT_METHOD()暴露 native 方法
3> 在 JS端經過 NativeModules獲取當前 native 模塊,調用模塊的方法,傳遞參數,同時支持回調,在native方法裏添加 block 回調或者 promise 回調,便可支持OC 回調傳遞結果給 JS
4> 導出常量原生模塊能夠導出一些常量,在JS 端能夠隨時訪問,用這種方法來傳遞一些靜態數據,能夠避免經過 Bridge 進行一次來回交互
- (NSDictionary *)constantsToExport
{
return @{ @"firstDayOfTheWeek": @"Monday" };
}
Js端訪問 console.log(CalendarManager.firstDayOfTheWeek);
RCT_REMAP_METHOD(testPromiseEvent,
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
NSArray *events =@[@"Promise ",@"test ",@" array"];
if (events) {
resolve(events);
} else {
NSError *error=[NSError errorWithDomain:@"我是Promise回調錯誤信息..." code:101 userInfo:nil];
reject(@"no_events", @"There were no events", error);
}
}
// 固然也能夠用這種 promise 的回調 在 js裏可使用 . then() 或者 async await 來獲取 promise 結果
//tips: 關於 RCT_EXPORT_METHOD() 能夠暴露方法給 JS 調用, 內部實現就是利用 runtime 遍歷該實例的方法, 過濾含有__ rct _export__的而後保存到模塊配置表中
二. OC 調用 JS(給 JS 發送事件)
即便沒有被js調用 本地模塊也能夠主動給 JS 發送事件通知, 最直接的方式是使用 eventDispatcher
#import "RCTBridge.h"
#import "RCTEventDispatcher.h"
@implementation CalendarManager
@synthesize bridge = _bridge;
// 進行設置發送事件通知給JavaScript端
- (void)calendarEventReminderReceived:(NSNotification *)notification
{
NSString *name = [notification userInfo][@"name"];
[self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder"
body:@{@"name": name}];
}
@end
在 js中能夠這樣訂閱事件import { NativeAppEventEmitter } from 'react-native';
var subscription = NativeAppEventEmitter.addListener(
'EventReminder',
(reminder) => console.log(reminder.name)
);
...
// 千萬不要忘記忘記取消訂閱, 一般在componentWillUnmount函數中實現。
subscription.remove();
三. RN 使用原生 UI 組件
1> 像原生自定義 UI 組件同樣, 新建 class 自定義視圖 , 這裏以一個能夠支持手勢縮放的相冊瀏覽視圖爲例
2> 新建 xxxViewManager 繼承自 RCTViewManager
3> RCT_EXPORT_MODULE(RCTPhotoView)導出模塊 RCT_EXPORT_VIEW_PROPERTY(imgURL, NSString); RCT_EXPORT_VIEW_PROPERTY(onSingleTap, RCTBubblingEventBlock);導出屬性和方法供 js 調用
4> 重寫 -(UIView *)View{ }的方法 返回自定義的UI 組件
5> 新建一個 JS 類 利用var RCTPhotoView = requireNativeComponent('RCTPhotoView', ImageBrowserView)
導出該自定義組件
6> 在須要的地方使用該組件(使用姿式與其餘組件同樣)
// ViewManager 的定義 .h
// 新建 JS 類導出該原生 UI 組件 使用的時候直接導入便可
// 使用 賦值 url屬性 實現原生組件的點擊方法的回調
// 最後說下 RN 的線程管理
RN 最主要的有兩個線程, UI MainThread 和 JSThread, UIThread 建立一個事件循環以後, 就一直有個 runloop 維持, 不斷接收處理 App 事件, JSThread更像一個底層數據採集器, 不斷上傳數據和事件, ios 經過 JavascriptCore 提供的 js Bridge, UIThread將這些事件和數據轉化爲 UI 改變, UI main thread 跟 JS thread更像是CS 模型,JS thread更像服務端, UI main thread是客戶端, UI main thread 不斷詢問JS thread而且請求數據,若是數據有變,則更新UI界面。
//RCTJavaScriptContext javascriptCore 引擎初始化
js 自己是單線程語言, native 是多線程機制, 那麼 js如何來使用 native 的多線程, 或者說如何讓js在其餘線程執行
在 iOS 開發中,一談到線程管理,確定離不開 GCD(Grand Central Dispatch)與 NSOperation/NSOperationQueue 技術選型上的爭論。關於這二者廣泛的觀點爲:GCD 較輕量,使用起來較靈活,但在任務依賴、併發數控制、任務狀態控制(線程取消/掛起/恢復/監控)等方面存在先天不足;NSOperation/NSOperationQueue 基於 GCD 作的封裝,使用較重,在某些情景下性能不如 GCD,但在併發環境下複雜任務處理能很好地知足一些特性,業務擴展性較好。
global.nativeFlushQueueImmediate 是Native提供的接口,__nativeCall把須要調用的module,method,params都塞到隊列裏,而後傳遞到Native
__nativeCall(module, method, params, onFail, onSucc) {
this._queue[MODULE_IDS].push(module); this._queue[METHOD_IDS].push(method); this._queue[PARAMS].push(params); global.nativeFlushQueueImmediate(this._queue); this._queue = [[],[],[]]; this._lastFlush = now;
}
Native模塊查詢接口:global.nativeRequireModuleConfig和調用接口global.nativeFlushQueueImmediate,他們是在JS引擎(JSContext)初始化時,定義到全局變量的。
先從 JS 端看起,JS 調用 Native 的邏輯在 MessageQueue.js 的 _nativeCall 方法中。在最小調用間隔(MIN_TIME_BETWEEN_FLUSHES_MS=5ms)內,JS 端會將調用信息存儲在 _queue 數組中,經過 global. nativeFlushQueueImmediate 方法來調用 Native 端的功能。global.nativeFlushQueueImmediate 方法在 iOS 端映射的是一個全局的 Block,如圖
nativeFlushQueueImmediate 在這裏只是作了一箇中轉,功能的實現是經過調用 RCTBatchedBridge.m 中的 handleBuffer 方法。在 handleBuffer 中針對每一個組件使用一個 queue 來處理對應任務。其中,這個 queue 是組件數據 RCTModuleData 中的屬性 methodQueue,後文會詳細介紹。
雖然 JS 只具有單線程操做的能力,但經過利用 Native 端多線程處理能力,仍能夠很好地處理 RN 中的任務。回到剛開始拋出的問題,RN 在這裏用 GCD 而非 NSOperationQueue 來處理線程,主要緣由有:
// 自定義UI 組件的線程管理
Native(iOS)端處理併發任務的線程是 RCTModuleData 中的屬性 methodQueue。RCTModuleData 是對組件對象的實例(instance)、方法(methods)、所屬線程(methodQueue)等方面的描述。每個 module 都有個獨立的線程來管理,具體線程的初始化在 RCTModuleData 的 setUpMethodQueue 中進行設置
這個方法開放了給組件自定義線程的接口。若是組件實現了 methodQueue 方法,則獲取此方法中設置的 queue;不然默認建立一個子線程
是否是發現除了默認的 React-native 線程和主線程還有一個 RCTJSThread ,這是個什麼東西, 看圖:
說的很清楚了吧, 他不是一個線程,而是一個隊列, 可以使 method 強制回到 js線程執行,
- (dispatch_queue_t)methodQueue
{
return RCTJSThread;
}這樣寫 回到 js線程
// RCTUIManagerQueue
RN 中的 UI 操做都是在 RCTUIManagerQueue 中進行的, 他是一個併發隊列,可是優先級是最高的, 因爲蘋果在 iOS 8.0 以後引入了 NSQualityOfService,淡化了原有的線程優先級概念,因此 RN 在這裏優先使用了 8.0 的新功能,而對 8.0 如下的沿用原有的方式。但不論用哪一種方式,都保證 RCTUIManagerQueue 在併發隊列中優先級是最高的。到這裏或許有疑問了,UI 操做不是要在主線程裏操做嗎,這裏爲何是在一個子線程中操做?其實在此執行的是 UI 的準備工做,當真正須要把 UI 元素加入主界面,開始圖形繪製時,才須要在主線程裏操做
在這裡回到主線程操做
End