最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

ReactNative原理與核心知識點(diǎn)

2023-06-21 17:58 作者:Cpp程序員  | 我要投稿

React Native特點(diǎn)

跨平臺

使用js寫出頁面組件代碼被React框架統(tǒng)一轉(zhuǎn)成Virtual DOM樹,Virtual DOM樹是UI結(jié)構(gòu)的一層抽象,可以被轉(zhuǎn)換成任何支持端的UI視圖。

ReactNative框架將Virtual DOM 轉(zhuǎn)成原APP的UIView樹。

熱修復(fù)

ReactNative的產(chǎn)物bundle包,bundle包中包含的為RN業(yè)務(wù)所需要的所有資源,包括代碼和資源。bundle的加載方式是APP啟動(dòng)時(shí)從后臺下載,然后通過js虛擬機(jī)執(zhí)行的。

所以可以將每次業(yè)務(wù)迭代修改后的代碼上傳到服務(wù),進(jìn)行用戶無感知版本更新。

注意:

bundle中的業(yè)務(wù)代碼不能修改APP現(xiàn)有的原生行為,不能調(diào)用私有API,不然禁止上架。

bundle包中的js是經(jīng)過babel轉(zhuǎn)義后的普通js,而非jsx語法糖。

?

JS與Native交互的基本原理

JS引擎

iOS側(cè)使用的JavaScriptCore作為bundle產(chǎn)物的js執(zhí)行引擎。

JS與Native交互的基本原理很簡單,就是在JS的全局上下文添加成員變量。原生調(diào)用JS是JS在JS上下文中添加方法成員變量,然后原生調(diào)用。JS調(diào)用原生是原生往JS上下文中添加方法成員變量,然后JS調(diào)用。

JS調(diào)用原生

通過將block對象賦值給js全局上下文中的全局變量,js內(nèi)部調(diào)用這個(gè)全局方法進(jìn)行執(zhí)行。

1
2
3
4
ctx[@"NativeMethod"] = ^(NSString *name) {
????// do something
????return?someResult
}

原生調(diào)用JS

先創(chuàng)建一個(gè)JS上下文對象,在上下文中添加方法的全局變量。原生獲取上下文的全局變量Value, 然后調(diào)用,執(zhí)行這個(gè)JS方法。

1
2
3
4
5
6
7
8
9
10
11
12
// 創(chuàng)建一個(gè)ctx的JS上下文
JSContent *ctx = [[JSContent alloc] init];
// 創(chuàng)建一個(gè)變量name
[ctx evaluateScript:@"var name = 'jack'"];
// 創(chuàng)建一個(gè)方法
[ctx evaluateScript:@"var sayHi = function(name) { return 'hello ' + name }"];
?
?
// 通過ctx上下文對象,獲取到hello方法
JSValue *sayHiUnction = ctx[@"sayHi"];
// 運(yùn)行js方法
JSValue *greetings = [sayHiUnction callWithArguments:@[@"jack"];?// hello jack

ReactNative框架中原生與JS的調(diào)用基本思路也是這種,只不過考慮到大量的Native對象注冊會污染js引擎中的上下文,增加了一層Bridge。

原生和JS之間的交互都是通過Bridge這個(gè)通道,通過里面的幾個(gè)基礎(chǔ)方法進(jìn)行交互。原生與JS的交互是異步的。

另外,F(xiàn)acebook為了提升RN框架中JS的執(zhí)行效率,專門推出了一個(gè)JS引擎 Hermes, 在關(guān)鍵指標(biāo)上,相比于JSCore,V8提升了不少,比較易于RN框架集成。

?

ReactNative核心知識

RCTBridge:?ReactNative中原生與JS交互的通道

RCTBridge用于給js引擎提供原生擴(kuò)展接口。將原生功能如定位,3D等通過Bridge將其封裝成JS接口,然后注入到j(luò)s引擎的上下文中。

RN框架啟動(dòng)的簡單流程為:首先將js代碼加載到內(nèi)存,然后創(chuàng)建RCTBridge實(shí)例,然后創(chuàng)建RCTRootContentView內(nèi)容展示的容器視圖,然后調(diào)用JS上下文中AppRegistry對象的runApplication方法,并將@[moduleName, appParameters]組件名,參數(shù)傳遞給JS。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// RCTRootView.m
- (void)javaScriptDidLoad:(NSNotification?*)notification
{
??RCTAssertMainQueue();
??RCTBridge *bridge = notification.userInfo[@"bridge"];
??if?(bridge != _contentView.bridge) {
????[self?bundleFinishedLoading:bridge];
??}
}
?
- (void)bundleFinishedLoading:(RCTBridge *)bridge
{
??// 省略創(chuàng)建RCTRootContentView...
?
??[self?runApplication:bridge];
?
??// 省略添加一個(gè)RCTRootContentView...
}
?
- (void)runApplication:(RCTBridge *)bridge
{
??NSString?*moduleName = _moduleName ?: @"";?// 這里是@"NewProject"
??NSDictionary?*appParameters = @{
????@"rootTag": _contentView.reactTag,
????@"initialProps": _appProperties ?: @{},
??};
?
??[bridge enqueueJSCall:@"AppRegistry"?????????????????method:@"runApplication"???????????????????args:@[moduleName, appParameters]
?????????????completion:NULL];
}

?

原生調(diào)用JS

在JS上下文中,調(diào)用JS的方式是通過方法:global.batchedBridge.callFunctionReturnFlushedQueue

?

所以RN在原生側(cè)的的JS引擎的封裝對象中使用成員變量保存了這個(gè)JS的函數(shù)指針,原生調(diào)用JS時(shí),通過傳遞參數(shù) moduleid 和 methodid 完成方法的調(diào)用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void?JSIExecutor::bindBridge() {
??std::call_once(bindFlag_, [this] {
????SystraceSection?s("JSIExecutor::bindBridge (once)");
????Value?batchedBridgeValue?=
????????runtime_->global().getProperty(*runtime_,?"__fbBatchedBridge");
????if?(batchedBridgeValue.isUndefined() || !batchedBridgeValue.isObject()) {
??????throw?JSINativeException(
??????????"Could not get BatchedBridge, make sure your bundle is packaged correctly");
????}
?
????Object?batchedBridge?=?batchedBridgeValue.asObject(*runtime_);
????callFunctionReturnFlushedQueue_?=?batchedBridge.getPropertyAsFunction(
????????*runtime_,?"callFunctionReturnFlushedQueue");
????invokeCallbackAndReturnFlushedQueue_?=?batchedBridge.getPropertyAsFunction(
????????*runtime_,?"invokeCallbackAndReturnFlushedQueue");
????flushedQueue_?=
????????batchedBridge.getPropertyAsFunction(*runtime_,?"flushedQueue");
??});
}

?

JS調(diào)用原生

JS調(diào)用原生通常是通過原生主動(dòng)處理_eventQueue中的事件,特殊情況會直接調(diào)用原生注冊給JS的nativeFlushQueueImmediate方法, 并傳遞moduleName 、methodName、callback 參數(shù)給這個(gè)方法完成調(diào)用。

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
void?JSIExecutor::initializeRuntime() {
??SystraceSection?s("JSIExecutor::initializeRuntime");
??runtime_->global().setProperty(
??????*runtime_,
??????"nativeModuleProxy",
??????Object::createFromHostObject(
??????????*runtime_,?std::make_shared<NativeModuleProxy>(nativeModules_)));
?
??runtime_->global().setProperty(
??????*runtime_,
??????"nativeFlushQueueImmediate",
??????Function::createFromHostFunction(
??????????*runtime_,
??????????PropNameID::forAscii(*runtime_,?"nativeFlushQueueImmediate"),
??????????1,
??????????[this](
??????????????jsi::Runtime?&,
??????????????const?jsi::Value?&,
??????????????const?jsi::Value?*args,
??????????????size_t?count) {
????????????if?(count?!=?1) {
??????????????throw?std::invalid_argument(
??????????????????"nativeFlushQueueImmediate arg count must be 1");
????????????}
????????????callNativeModules(args[0],?false);
????????????return?Value::undefined();
??????????}));
?
??runtime_->global().setProperty(
??????*runtime_,
??????"nativeCallSyncHook",
??????Function::createFromHostFunction(
??????????*runtime_,
??????????PropNameID::forAscii(*runtime_,?"nativeCallSyncHook"),
??????????1,
??????????[this](
??????????????jsi::Runtime?&,
??????????????const?jsi::Value?&,
??????????????const?jsi::Value?*args,
??????????????size_t?count) {?return?nativeCallSyncHook(args,?count); }));
?
??runtime_->global().setProperty(
??????*runtime_,
??????"globalEvalWithSourceUrl",
??????Function::createFromHostFunction(
??????????*runtime_,
??????????PropNameID::forAscii(*runtime_,?"globalEvalWithSourceUrl"),
??????????1,
??????????[this](
??????????????jsi::Runtime?&,
??????????????const?jsi::Value?&,
??????????????const?jsi::Value?*args,
??????????????size_t?count) {?return?globalEvalWithSourceUrl(args,?count); }));
?
??if?(runtimeInstaller_) {
????runtimeInstaller_(*runtime_);
??}
??bool?hasLogger(ReactMarker::logTaggedMarker);
??if?(hasLogger) {
????ReactMarker::logMarker(ReactMarker::CREATE_REACT_CONTEXT_STOP);
??}
}


Virtual DOM 虛擬DOM

?

虛擬DOM的特點(diǎn)

1.用于描述頁面的UI結(jié)構(gòu):在作用上虛擬DOM和普通的DOM是一樣的。

2.平臺無關(guān)性:虛擬DOM表示的UI結(jié)構(gòu)是對UI的一層抽象,它是平臺無關(guān)的。具體的UI渲染是交個(gè)具體的平臺渲染引擎進(jìn)行的,如iOS,安卓自身的渲染引擎。

虛擬DOM對標(biāo)簽的定義

虛擬DOM把標(biāo)簽分為2類:原子型標(biāo)簽,組合型標(biāo)簽。

原子型標(biāo)簽是平臺支持型的基礎(chǔ)標(biāo)簽,如果RCTView, RCTText。對應(yīng)瀏覽器頁面中,原子型標(biāo)簽有h1,li,div等。

組合型標(biāo)簽是用戶自定義的組件,它在虛擬DOM中對應(yīng)的是自定義標(biāo)簽構(gòu)造器函數(shù),頁面渲染時(shí)調(diào)用這個(gè)構(gòu)造函數(shù),創(chuàng)建一個(gè)實(shí)例,然后調(diào)用實(shí)例的render方法,組合型標(biāo)簽的render方法內(nèi)會把組合標(biāo)簽進(jìn)行拆解,最后拆解成基本的原子型標(biāo)簽。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var?ele?= {
????...
????type:?type,?// 元素的類型
????key:?key,?// 元素key標(biāo)示
????ref:?ref,?// 元素的引用
????props:?props,?// 元素的參數(shù),包含children
????...
}
?
// example 1
<div>hello</div>
// 會被描述為
?
{type: 'div',
????props: {
????????children: ['hello']
????}
}
?
// example 2
<CustomerComponents?/>
// 會被描述為
{
????type:?CustomerComponents
}

?

UI渲染

RN框架與瀏覽器的對比:在瀏覽器中,JS通過調(diào)用DOM API創(chuàng)建UI視圖。在RN中,JS通過調(diào)用RCTUIManager來創(chuàng)建iOS,Android移動(dòng)端的UI視圖。

RN的UI渲染是基于虛擬DOM的,通過根據(jù)不同的平臺調(diào)用不同平臺的Bridge, Brideg再調(diào)用不同平臺的的RCTUIManager進(jìn)行UI的創(chuàng)建。

?

其他

三條線程

RN內(nèi)部有三條線程在同時(shí)運(yùn)行著:Shadow Thread, JS Thread, UI Thread。

JS Thread:JS線程,負(fù)責(zé)JS與原生的交互,它們的交互是異步的,每次調(diào)用都是將block放入隊(duì)列中,等js代碼執(zhí)行完后,讀取事件隊(duì)列進(jìn)行處理。

UI Thread:UI主線程,負(fù)責(zé)頁面的交互與渲染, 由RCTUIManager使用。

Shadow Thread: 負(fù)責(zé)將flex布局轉(zhuǎn)成Native的布局,由yago引擎使用。


三個(gè)隊(duì)列

RN框架內(nèi),原生與JS的交換類型分兩種:UI和事件,這2這種事件的處理都是異步的,它們都是將事件順序放置到隊(duì)列中,在合適的時(shí)機(jī)被調(diào)用。

事件的處理在RCTBridge中處理,UI的處理在RCTUIManager中處理。

JS調(diào)用原生異步事件隊(duì)列:_eventQueue隊(duì)列

原生調(diào)用JS異步事件隊(duì)列:_pendingCalls隊(duì)列

UI更新異步事件處理隊(duì)列:_pendingUIBlocks隊(duì)列


JSI

javascript interface js虛擬機(jī)通用接口層,是針對JS引擎封裝的上層API框架,使用JSI做JS引擎調(diào)用的優(yōu)點(diǎn):

1.底部可以任意替換JS引擎而不影響上層JS引擎的使用。如:可以任意替換JavaScript Core, V8等。

2.通過JSI,JavaScript可以持有C++宿主對象的引用,所以可以直接調(diào)用原生方法(UIView, NativeModule),它與現(xiàn)在統(tǒng)一使用Bridge這個(gè)通道和消息異步調(diào)用比起來,提高了消息發(fā)送的及時(shí)性,避免了消息隊(duì)列執(zhí)行的等待。


React Native核心知識在框架中的使用

?

React Native核心功能在RN項(xiàng)目啟動(dòng)時(shí)會進(jìn)行各自的初始化,生成bundle運(yùn)行上下文。在類型上可以分為2類:

1.JS與原生的事件處理:創(chuàng)建RCTBridge橋接通道。

2.UI交互與更新的事件處理:創(chuàng)建RCTRootView容器視圖。

APP啟動(dòng),React Native運(yùn)行環(huán)境初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (BOOL)application:(UIApplication?*)application?didFinishLaunchingWithOptions:(NSDictionary?*)launchOptions
{
??if?(!self.bridge) {
????self.bridge?= [self?createBridgeWithDelegate:self?launchOptions:launchOptions];
??}
?
??NSDictionary?*initProps?= [self?prepareInitialProps];
??UIView?*rootView?= [self?createRootViewWithBridge:self.bridge?moduleName:self.moduleName?initProps:initProps];
?
??if?(@available(iOS?13.0, *)) {
????rootView.backgroundColor?= [UIColor?systemBackgroundColor];
??}?else?{
????rootView.backgroundColor?= [UIColor?whiteColor];
??}
?
??self.window?= [[UIWindow?alloc]?initWithFrame:[UIScreen?mainScreen].bounds];
??UIViewController?*rootViewController?= [self?createRootViewController];
??rootViewController.view?=?rootView;
??self.window.rootViewController?=?rootViewController;
??[self.window?makeKeyAndVisible];
??return?YES;
}

?

JS與原生的事件處理:創(chuàng)建RCTBridge橋接通道

RCTBridge的主要邏輯是在batchedBridge中,主要初始化流程為:

1.初始化Native Modules

2.創(chuàng)建Native Modules配置表

3.準(zhǔn)備JS引擎工廠,創(chuàng)建JS引擎

4.將Modules配置信息注冊到JS引擎中

5.加載boundle代碼

6.執(zhí)行boundle代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
- (void)setUp
{
??RCT_PROFILE_BEGIN_EVENT(0, @"-[RCTBridge setUp]",?nil);
?
??//_performanceLogger日志工具初始化
?
??//_bundleURL獲取
?
??//batchedBridge創(chuàng)建
?
??self.batchedBridge?= [[bridgeClass?alloc]?initWithParentBridge:self];
??[self.batchedBridge?start];
?
??RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}
?
batchedBridgeRCTCXXBridge,它的初始化方法如下:
- (instancetype)initWithParentBridge:(RCTBridge?*)bridge
{
??RCTAssertParam(bridge);
?
??if?((self?= [super?initWithDelegate:bridge.delegate
????????????????????????????bundleURL:bridge.bundleURL
???????????????????????moduleProvider:bridge.moduleProvider
????????????????????????launchOptions:bridge.launchOptions])) {
????_parentBridge?=?bridge;
????_performanceLogger?= [bridge?performanceLogger];
?
????registerPerformanceLoggerHooks(_performanceLogger);
?
????/**
?????* Set Initial State
?????*/
????_valid?=?YES;
????_loading?=?YES;
????_moduleRegistryCreated?=?NO;
????_pendingCalls?= [NSMutableArray?new];
????_displayLink?= [RCTDisplayLink?new];
????_moduleDataByName?= [NSMutableDictionary?new];
????_moduleClassesByID?= [NSMutableArray?new];
????_moduleDataByID?= [NSMutableArray?new];
????_objCModuleRegistry?= [RCTModuleRegistry?new];
????[_objCModuleRegistry?setBridge:self];
????_bundleManager?= [RCTBundleManager?new];
????[_bundleManager?setBridge:self];
????_viewRegistry_DEPRECATED?= [RCTViewRegistry?new];
????[_viewRegistry_DEPRECATED?setBridge:self];
????_callableJSModules?= [RCTCallableJSModules?new];
????[_callableJSModules?setBridge:self];
?
????[RCTBridge?setCurrentBridge:self];
?
????[[NSNotificationCenter?defaultCenter]?addObserver:self
?????????????????????????????????????????????selector:@selector(handleMemoryWarning)
?????????????????????????????????????????????????name:UIApplicationDidReceiveMemoryWarningNotification
???????????????????????????????????????????????object:nil];
?
????RCTLogSetBridgeModuleRegistry(_objCModuleRegistry);
????RCTLogSetBridgeCallableJSModules(_callableJSModules);
??}
??return?self;
}
?
?
- (void)start
{
??RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways, @"-[RCTCxxBridge start]",?nil);
?
??[[NSNotificationCenter?defaultCenter]?postNotificationName:RCTJavaScriptWillStartLoadingNotification
??????????????????????????????????????????????????????object:_parentBridge
????????????????????????????????????????????????????userInfo:@{@"bridge"?:?self}];
?
??//啟動(dòng)JS線程
??_jsThread?= [[NSThread?alloc]?initWithTarget:[self?class]?selector:@selector(runRunLoop)?object:nil];
??_jsThread.name?=?RCTJSThreadName;
??_jsThread.qualityOfService?=?NSOperationQualityOfServiceUserInteractive;
#if?RCT_DEBUG
??_jsThread.stackSize?*=?2;
#endif
??[_jsThread?start];
?
??dispatch_group_t?prepareBridge?=?dispatch_group_create();
?
??[_performanceLogger?markStartForTag:RCTPLNativeModuleInit];
?
??//1.初始化Native Modules
??[self?registerExtraModules];
??//2.創(chuàng)建Native Modules配置表
??// Initialize all native modules that cannot be loaded lazily
??(void)[self?_initializeModules:RCTGetModuleClasses()?withDispatchGroup:prepareBridge?lazilyDiscovered:NO];
??[self?registerExtraLazyModules];
?
??[_performanceLogger?markStopForTag:RCTPLNativeModuleInit];
?
??// This doesnt really do anything.? The real work happens in initializeBridge.
??_reactInstance.reset(new?Instance);
?
??__weak?RCTCxxBridge?*weakSelf?=?self;
?
??// 3.準(zhǔn)備JS引擎工廠,創(chuàng)建JS引擎
??std::shared_ptr<JSExecutorFactory>?executorFactory;
??if?(!self.executorClass) {
????if?([self.delegate?conformsToProtocol:@protocol(RCTCxxBridgeDelegate)]) {
??????id<RCTCxxBridgeDelegate>?cxxDelegate?= (id<RCTCxxBridgeDelegate>)self.delegate;
??????executorFactory?= [cxxDelegate?jsExecutorFactoryForBridge:self];
????}
????// 4.將Modules配置信息注冊到JS引擎中
????if?(!executorFactory) {
??????auto?installBindings?=?RCTJSIExecutorRuntimeInstaller(nullptr);
#if?RCT_USE_HERMES
??????executorFactory?=?std::make_shared<HermesExecutorFactory>(installBindings);
#else
??????executorFactory?=?std::make_shared<JSCExecutorFactory>(installBindings);
#endif
????}
??}?else?{
????id<RCTJavaScriptExecutor>?objcExecutor?= [self?moduleForClass:self.executorClass];
????executorFactory.reset(new?RCTObjcExecutorFactory(objcExecutor, ^(NSError?*error) {
??????if?(error) {
????????[weakSelf?handleError:error];
??????}
????}));
??}
?
????//_turboModuleRegistry是一個(gè)TurboModule注冊表,TurboModule是JS在RN中的一種優(yōu)化方式,將常用的JS代碼編譯成可執(zhí)行代碼,提高執(zhí)行速度。
??/**
???* id<RCTCxxBridgeDelegate> jsExecutorFactory may create and assign an id<RCTTurboModuleRegistry> object to
???* RCTCxxBridge If id<RCTTurboModuleRegistry> is assigned by this time, eagerly initialize all TurboModules
???*/
??if?(_turboModuleRegistry?&&?RCTTurboModuleEagerInitEnabled()) {
????for?(NSString?*moduleName?in?[_turboModuleRegistry?eagerInitModuleNames]) {
??????[_turboModuleRegistry?moduleForName:[moduleName?UTF8String]];
????}
?
????for?(NSString?*moduleName?in?[_turboModuleRegistry?eagerInitMainQueueModuleNames]) {
??????if?(RCTIsMainQueue()) {
????????[_turboModuleRegistry?moduleForName:[moduleName?UTF8String]];
??????}?else?{
????????id<RCTTurboModuleRegistry>?turboModuleRegistry?=?_turboModuleRegistry;
????????dispatch_group_async(prepareBridge,?dispatch_get_main_queue(), ^{
??????????[turboModuleRegistry?moduleForName:[moduleName?UTF8String]];
????????});
??????}
????}
??}
?
??// Dispatch the instance initialization as soon as the initial module metadata has
??// been collected (see initModules)
??dispatch_group_enter(prepareBridge);
??[self?ensureOnJavaScriptThread:^{
????[weakSelf?_initializeBridge:executorFactory];
????dispatch_group_leave(prepareBridge);
??}];
?
??// 5.加載boundle代碼
??// Load the source asynchronously, then store it for later execution.
??dispatch_group_enter(prepareBridge);
??__block?NSData?*sourceCode;
??[self
??????loadSource:^(NSError?*error,?RCTSource?*source) {
????????if?(error) {
??????????[weakSelf?handleError:error];
????????}
?
????????sourceCode?=?source.data;
????????dispatch_group_leave(prepareBridge);
??????}
??????onProgress:^(RCTLoadingProgress?*progressData) { }];
?
??// 模塊和js代碼加載完成后,執(zhí)行js代碼
??// Wait for both the modules and source code to have finished loading
??dispatch_group_notify(prepareBridge,?dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE,?0), ^{
????RCTCxxBridge?*strongSelf?=?weakSelf;
????if?(sourceCode?&&?strongSelf.loading) {
??????// 6.執(zhí)行boundle代碼
??????[strongSelf?executeSourceCode:sourceCode?sync:NO];
????}
??});
??RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
}

?

初始化Native Modules與創(chuàng)建Native Modules配置表

把本地的RN模塊都收集起來,包括RN框架自帶的和用戶自定義的,將模塊信息保存到Bridge的變量中,用于與JS交換。

_moduleDataByName = [NSMutableDictionary new];

_moduleClassesByID = [NSMutableArray new];

_moduleDataByID = [NSMutableArray new];

?

JS發(fā)送消息到Native時(shí),通過- (id)moduleForName:(const char *)moduleName;查詢到模塊詳情,進(jìn)行模塊調(diào)用。

_objCModuleRegistry = [RCTModuleRegistry new];

[_objCModuleRegistry setBridge:self];


準(zhǔn)備JS引擎工廠,創(chuàng)建JS引擎與將Modules配置信息注冊到JS引擎中

RN將Native Modules信息收集完成后保存到成員變量中,這個(gè)成員變量是一個(gè)數(shù)組。使用moduleConfig保存模塊的模塊名,方法名。然后將這些數(shù)據(jù)注入到JS引擎中。

JS調(diào)用原生時(shí),通過模塊名,方法名,參數(shù)調(diào)用原生方法。在原生調(diào)用JS時(shí),會將調(diào)用放入_pendingCalls隊(duì)列中,進(jìn)行異步執(zhí)行。而JS調(diào)原生是將調(diào)用放入到_eventQueue隊(duì)列中,進(jìn)行異步執(zhí)行。

JS可以通過方法nativeFlushQueueImmediate直接調(diào)用Native,但是一般JS不會這樣做,而是等原生自己去_eventQueue隊(duì)列中自己去取任務(wù)做處理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// js thread only (which surprisingly can be the main thread, depends on used JS executor)
- (void)flushEventsQueue
{
??[_eventQueueLock?lock];
??NSDictionary?*events?=?_events;
??_events?= [NSMutableDictionary?new];
??NSMutableArray?*eventQueue?=?_eventQueue;
??_eventQueue?= [NSMutableArray?new];
??_eventsDispatchScheduled?=?NO;
??[_eventQueueLock?unlock];
?
??for?(NSNumber?*eventId?in?eventQueue) {
????[self?dispatchEvent:events[eventId]];
??}
}

?

UI交互與更新的事件處理:創(chuàng)建RCTRootView容器視圖

?

RCTRootView為RN頁面的入口,在RCTRootView初始化過程中,會創(chuàng)建RCTRootContentView作為內(nèi)容視圖放置在RCTRootView的底部作為根視圖。

RCTRootContentView的初始化方法中,在uiManager中將RCTRootContentView注冊成根視圖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (instancetype)initWithFrame:(CGRect)frame
???????????????????????bridge:(RCTBridge?*)bridge
?????????????????????reactTag:(NSNumber?*)reactTag
???????????????sizeFlexiblity:(RCTRootViewSizeFlexibility)sizeFlexibility
{
??if?((self?= [super?initWithFrame:frame])) {
????_bridge?=?bridge;
????self.reactTag?=?reactTag;
????_sizeFlexibility?=?sizeFlexibility;
????_touchHandler?= [[RCTTouchHandler?alloc]?initWithBridge:_bridge];
????[_touchHandler?attachToView:self];
????[_bridge.uiManager?registerRootView:self];
??}
??return?self;
}

RCTUIManager是RN中UI的管理者,它負(fù)責(zé)處理所有與UI相關(guān)的事情,如:注入到JS中的創(chuàng)建View方法。

在createView方法中可以看到,RN對View的操作都是雙份的,分別作用在RCTShadowView和UIView上。RCTShadowView和UIView的關(guān)系類似于虛擬DOM和DOM的關(guān)系。

RCTShadowView是一個(gè)虛擬DOM樹,是一個(gè)結(jié)構(gòu)體,用于描述視圖的樣式和事件,比較輕量級。

在RN中當(dāng)調(diào)用setState更新組件狀態(tài)時(shí),就會生成一個(gè)新的虛擬DOM,然后RN將新的虛擬DOM與舊的虛擬DOM進(jìn)行Diff對比,生成差異對象,然后遍歷差異對象,將所有的改動(dòng)更新到UI上。而更新到了Native是先更新到RCTShadowView上,等合適的時(shí)候再統(tǒng)一更新到UI上。


UI更新操作也是異步的,更新任務(wù)被放置在_pendingUIBlocks隊(duì)列上,在UI變化時(shí)或Bridge批出來結(jié)束時(shí)刷新這個(gè)隊(duì)列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
RCT_EXPORT_METHOD(createView
??????????????????: (nonnull?NSNumber?*)reactTag?viewName
??????????????????: (NSString?*)viewName?rootTag
??????????????????: (nonnull?NSNumber?*)rootTag?props
??????????????????: (NSDictionary?*)props)
{
??RCTComponentData?*componentData?=?_componentDataByName[viewName];
??if?(componentData?==?nil) {
????RCTLogError(@"No component found for view with name \"%@\"",?viewName);
??}
?
??// Register shadow view
??RCTShadowView?*shadowView?= [componentData?createShadowViewWithTag:reactTag];
??if?(shadowView) {
????[componentData?setProps:props?forShadowView:shadowView];
????_shadowViewRegistry[reactTag] =?shadowView;
????RCTShadowView?*rootView?=?_shadowViewRegistry[rootTag];
????RCTAssert(
????????[rootView?isKindOfClass:[RCTRootShadowView?class]] || [rootView?isKindOfClass:[RCTSurfaceRootShadowView?class]],
????????@"Given `rootTag` (%@) does not correspond to a valid root shadow view instance.",
????????rootTag);
????shadowView.rootView?= (RCTRootShadowView?*)rootView;
??}
?
??// Dispatch view creation directly to the main thread instead of adding to
??// UIBlocks array. This way, it doesnt get deferred until after layout.
??__block?UIView?*preliminaryCreatedView?=?nil;
?
??void?(^createViewBlock)(void) = ^{
????// Do nothing on the second run.
????if?(preliminaryCreatedView) {
??????return;
????}
?
????preliminaryCreatedView?= [componentData?createViewWithTag:reactTag?rootTag:rootTag];
?
????if?(preliminaryCreatedView) {
??????self->_viewRegistry[reactTag] =?preliminaryCreatedView;
????}
??};
?
??// We cannot guarantee that asynchronously scheduled block will be executed
??// *before* a block is added to the regular mounting process (simply because
??// mounting process can be managed externally while the main queue is
??// locked).
??// So, we positively dispatch it asynchronously and double check inside
??// the regular mounting block.
?
??RCTExecuteOnMainQueue(createViewBlock);
?
??[self?addUIBlock:^(__unused?RCTUIManager?*uiManager,?__unused?NSDictionary<NSNumber?*,?UIView?*>?*viewRegistry) {
????createViewBlock();
?
????if?(preliminaryCreatedView) {
??????[componentData?setProps:props?forView:preliminaryCreatedView];
????}
??}];
?
??[self?_shadowView:shadowView?didReceiveUpdatedProps:[props?allKeys]];
}


ReactNative原理與核心知識點(diǎn)的評論 (共 條)

分享到微博請遵守國家法律
青河县| 宁晋县| 陕西省| 焉耆| 西贡区| 拉萨市| 建德市| 汾阳市| 通海县| 新乡市| 滦南县| 南平市| 遵化市| 廊坊市| 桂东县| 鸡泽县| 江安县| 临潭县| 石景山区| 苏尼特右旗| 邓州市| 海林市| 成武县| 惠州市| 都昌县| 台东市| 揭阳市| 三河市| 葫芦岛市| 姚安县| 永嘉县| 冀州市| 农安县| 崇文区| 定陶县| 余干县| 得荣县| 河东区| 维西| 清流县| 凌海市|