Skip to content

Commit eab390a

Browse files
committed
Cleanup bridge init, measure native module init time
1 parent 8d07df4 commit eab390a

File tree

6 files changed

+91
-88
lines changed

6 files changed

+91
-88
lines changed

React/Base/RCTBatchedBridge.m

Lines changed: 68 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -113,27 +113,26 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge
113113

114114
- (void)start
115115
{
116-
__weak RCTBatchedBridge *weakSelf = self;
117-
118-
__block NSString *sourceCode;
119-
__block NSString *config;
120-
121116
dispatch_queue_t bridgeQueue = dispatch_queue_create("com.facebook.react.RCTBridgeQueue", DISPATCH_QUEUE_CONCURRENT);
122-
dispatch_group_t initModulesAndLoadSource = dispatch_group_create();
123117

118+
dispatch_group_t initModulesAndLoadSource = dispatch_group_create();
124119
dispatch_group_enter(initModulesAndLoadSource);
125-
[weakSelf loadSource:^(NSError *error, NSString *source) {
126-
if (error) {
127-
RCTLogError(@"%@", error);
128-
} else {
129-
sourceCode = source;
130-
}
131-
120+
__block NSString *sourceCode;
121+
[self loadSource:^(NSError *error, NSString *source) {
122+
sourceCode = source;
132123
dispatch_group_leave(initModulesAndLoadSource);
133124
}];
134125

126+
// Synchronously initialize all native modules
135127
[self initModules];
136128

129+
if (RCTProfileIsProfiling()) {
130+
// Depends on moduleDataByID being loaded
131+
RCTProfileHookModules(self);
132+
}
133+
134+
__weak RCTBatchedBridge *weakSelf = self;
135+
__block NSString *config;
137136
dispatch_group_enter(initModulesAndLoadSource);
138137
dispatch_async(bridgeQueue, ^{
139138
dispatch_group_t setupJSExecutorAndModuleConfig = dispatch_group_create();
@@ -144,16 +143,16 @@ - (void)start
144143
dispatch_group_async(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
145144
if (weakSelf.isValid) {
146145
config = [weakSelf moduleConfig];
147-
148-
if (RCTProfileIsProfiling()) {
149-
RCTProfileHookModules(weakSelf);
150-
}
151146
}
152147
});
153148

154149
dispatch_group_notify(setupJSExecutorAndModuleConfig, bridgeQueue, ^{
155-
[weakSelf injectJSONConfiguration:config onComplete:^(__unused NSError *error) {}];
156-
150+
// We're not waiting for this complete to leave the dispatch group, since
151+
// injectJSONConfiguration and executeSourceCode will schedule operations on the
152+
// same queue anyway.
153+
[weakSelf injectJSONConfiguration:config onComplete:^(__unused NSError *error) {
154+
RCTPerformanceLoggerEnd(RCTPLNativeModuleInit);
155+
}];
157156
dispatch_group_leave(initModulesAndLoadSource);
158157
});
159158
});
@@ -167,51 +166,52 @@ - (void)start
167166

168167
- (void)loadSource:(RCTSourceLoadBlock)_onSourceLoad
169168
{
170-
RCTPerformanceLoggerStart(RCTPLScriptDownload);
171-
int cookie = RCTProfileBeginAsyncEvent(0, @"JavaScript download", nil);
172-
173-
RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSString *source) {
174-
RCTPerformanceLoggerEnd(RCTPLScriptDownload);
175-
RCTProfileEndAsyncEvent(0, @"init,download", cookie, @"JavaScript download", nil);
176-
177-
if (error) {
178-
NSArray *stack = [error userInfo][@"stack"];
179-
if (stack) {
180-
[self.redBox showErrorMessage:error.localizedDescription
181-
withStack:stack];
182-
} else {
183-
[self.redBox showErrorMessage:error.localizedDescription
184-
withDetails:error.localizedFailureReason];
185-
}
169+
RCTPerformanceLoggerStart(RCTPLScriptDownload);
170+
int cookie = RCTProfileBeginAsyncEvent(0, @"JavaScript download", nil);
186171

187-
NSDictionary *userInfo = @{@"bridge": self, @"error": error};
188-
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidFailToLoadNotification
189-
object:_parentBridge
190-
userInfo:userInfo];
191-
}
172+
RCTSourceLoadBlock onSourceLoad = ^(NSError *error, NSString *source) {
173+
RCTProfileEndAsyncEvent(0, @"init,download", cookie, @"JavaScript download", nil);
174+
RCTPerformanceLoggerEnd(RCTPLScriptDownload);
192175

193-
_onSourceLoad(error, source);
194-
};
176+
if (error) {
177+
NSArray *stack = [error userInfo][@"stack"];
178+
if (stack) {
179+
[self.redBox showErrorMessage:error.localizedDescription
180+
withStack:stack];
181+
} else {
182+
[self.redBox showErrorMessage:error.localizedDescription
183+
withDetails:error.localizedFailureReason];
184+
}
195185

196-
if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:withBlock:)]) {
197-
[self.delegate loadSourceForBridge:_parentBridge withBlock:onSourceLoad];
198-
} else if (self.bundleURL) {
199-
[RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onComplete:onSourceLoad];
200-
} else {
201-
// Allow testing without a script
202-
dispatch_async(dispatch_get_main_queue(), ^{
203-
_loading = NO;
204-
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
205-
object:_parentBridge
206-
userInfo:@{ @"bridge": self }];
207-
});
208-
onSourceLoad(nil, nil);
186+
NSDictionary *userInfo = @{@"bridge": self, @"error": error};
187+
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidFailToLoadNotification
188+
object:_parentBridge
189+
userInfo:userInfo];
209190
}
191+
192+
_onSourceLoad(error, source);
193+
};
194+
195+
if ([self.delegate respondsToSelector:@selector(loadSourceForBridge:withBlock:)]) {
196+
[self.delegate loadSourceForBridge:_parentBridge withBlock:onSourceLoad];
197+
} else if (self.bundleURL) {
198+
[RCTJavaScriptLoader loadBundleAtURL:self.bundleURL onComplete:onSourceLoad];
199+
} else {
200+
// Allow testing without a script
201+
dispatch_async(dispatch_get_main_queue(), ^{
202+
_loading = NO;
203+
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
204+
object:_parentBridge
205+
userInfo:@{ @"bridge": self }];
206+
});
207+
onSourceLoad(nil, nil);
208+
}
210209
}
211210

212211
- (void)initModules
213212
{
214213
RCTAssertMainThread();
214+
RCTPerformanceLoggerStart(RCTPLNativeModuleInit);
215215

216216
// Register passed-in module instances
217217
NSMutableDictionary *preregisteredModules = [NSMutableDictionary new];
@@ -266,7 +266,6 @@ - (void)initModules
266266
_javaScriptExecutor = _modulesByName[RCTBridgeModuleNameForClass(self.executorClass)];
267267

268268
for (id<RCTBridgeModule> module in _modulesByName.allValues) {
269-
270269
// Bridge must be set before moduleData is set up, as methodQueue
271270
// initialization requires it (View Managers get their queue by calling
272271
// self.bridge.uiManager.methodQueue)
@@ -288,7 +287,6 @@ - (void)initModules
288287
- (void)setupExecutor
289288
{
290289
[_javaScriptExecutor setUp];
291-
292290
}
293291

294292
- (NSString *)moduleConfig
@@ -309,7 +307,7 @@ - (NSString *)moduleConfig
309307
- (void)injectJSONConfiguration:(NSString *)configJSON
310308
onComplete:(void (^)(NSError *))onComplete
311309
{
312-
if (!self.isValid) {
310+
if (!self.valid) {
313311
return;
314312
}
315313

@@ -325,9 +323,7 @@ - (void)injectJSONConfiguration:(NSString *)configJSON
325323

326324
- (void)executeSourceCode:(NSString *)sourceCode
327325
{
328-
_loading = NO;
329-
330-
if (!self.isValid || !_javaScriptExecutor) {
326+
if (!self.valid || !_javaScriptExecutor) {
331327
return;
332328
}
333329

@@ -336,22 +332,23 @@ - (void)executeSourceCode:(NSString *)sourceCode
336332
sourceCodeModule.scriptText = sourceCode;
337333

338334
[self enqueueApplicationScript:sourceCode url:self.bundleURL onComplete:^(NSError *loadError) {
339-
340335
if (loadError) {
341336
[self.redBox showError:loadError];
342337
return;
343338
}
344339

345-
/**
346-
* Register the display link to start sending js calls after everything
347-
* is setup
348-
*/
340+
// Register the display link to start sending js calls after everything is setup
349341
NSRunLoop *targetRunLoop = [_javaScriptExecutor isKindOfClass:[RCTContextExecutor class]] ? [NSRunLoop currentRunLoop] : [NSRunLoop mainRunLoop];
350342
[_jsDisplayLink addToRunLoop:targetRunLoop forMode:NSRunLoopCommonModes];
351343

352-
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
353-
object:_parentBridge
354-
userInfo:@{ @"bridge": self }];
344+
// Perform the state update and notification on the main thread, so we can't run into
345+
// timing issues with RCTRootView
346+
dispatch_async(dispatch_get_main_queue(), ^{
347+
_loading = NO;
348+
[[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification
349+
object:_parentBridge
350+
userInfo:@{ @"bridge": self }];
351+
});
355352
}];
356353
}
357354

@@ -420,12 +417,13 @@ - (NSDictionary *)modules
420417

421418
- (void)invalidate
422419
{
423-
if (!self.isValid) {
420+
if (!self.valid) {
424421
return;
425422
}
426423

427424
RCTAssertMainThread();
428425

426+
_loading = NO;
429427
_valid = NO;
430428
if ([RCTBridge currentBridge] == self) {
431429
[RCTBridge setCurrentBridge:nil];

React/Base/RCTBridge.m

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,8 @@ - (instancetype)initWithBundleURL:(NSURL *)bundleURL
186186
_bundleURL = bundleURL;
187187
_moduleProvider = block;
188188
_launchOptions = [launchOptions copy];
189-
[self bindKeys];
190189
[self setUp];
190+
[self bindKeys];
191191
}
192192
return self;
193193
}
@@ -214,21 +214,18 @@ - (void)bindKeys
214214
object:nil];
215215

216216
#if TARGET_IPHONE_SIMULATOR
217-
218217
RCTKeyCommands *commands = [RCTKeyCommands sharedInstance];
219218

220219
// reload in current mode
221220
[commands registerKeyCommandWithInput:@"r"
222221
modifierFlags:UIKeyModifierCommand
223-
action:^(__unused UIKeyCommand *command)
224-
{
222+
action:^(__unused UIKeyCommand *command) {
225223
[[NSNotificationCenter defaultCenter] postNotificationName:RCTReloadNotification
226224
object:nil
227225
userInfo:nil];
228226
}];
229227

230228
#endif
231-
232229
}
233230

234231
- (RCTEventDispatcher *)eventDispatcher
@@ -260,6 +257,11 @@ - (BOOL)isLoading
260257
return _batchedBridge.loading;
261258
}
262259

260+
- (BOOL)isValid
261+
{
262+
return _batchedBridge.valid;
263+
}
264+
263265
- (void)invalidate
264266
{
265267
RCTAssertMainThread();

React/Base/RCTPerformanceLogger.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
#import <Foundation/Foundation.h>
1111

1212
#import "RCTDefines.h"
13-
#import "RCTBridgeModule.h"
1413

1514
typedef NS_ENUM(NSUInteger, RCTPLTag) {
1615
RCTPLScriptDownload = 0,
17-
RCTPLAppScriptExecution,
16+
RCTPLScriptExecution,
17+
RCTPLNativeModuleInit,
1818
RCTPLTTI,
1919
RCTPLSize
2020
};

React/Base/RCTPerformanceLogger.m

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ void RCTPerformanceLoggerEnd(RCTPLTag tag)
2727
NSArray *RCTPerformanceLoggerOutput(void)
2828
{
2929
return @[
30-
@(RCTPLData[0][0]),
31-
@(RCTPLData[0][1]),
32-
@(RCTPLData[1][0]),
33-
@(RCTPLData[1][1]),
34-
@(RCTPLData[2][0]),
35-
@(RCTPLData[2][1]),
30+
@(RCTPLData[RCTPLScriptDownload][0]),
31+
@(RCTPLData[RCTPLScriptDownload][1]),
32+
@(RCTPLData[RCTPLScriptExecution][0]),
33+
@(RCTPLData[RCTPLScriptExecution][1]),
34+
@(RCTPLData[RCTPLNativeModuleInit][0]),
35+
@(RCTPLData[RCTPLNativeModuleInit][1]),
36+
@(RCTPLData[RCTPLTTI][0]),
37+
@(RCTPLData[RCTPLTTI][1]),
3638
];
3739
}
3840

@@ -71,6 +73,7 @@ - (void)sendTimespans
7173
@[
7274
@"ScriptDownload",
7375
@"ScriptExecution",
76+
@"NativeModuleInit",
7477
@"TTI",
7578
],
7679
]];

React/Base/RCTRootView.m

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,9 @@ - (void)hideLoadingView
160160

161161
- (void)javaScriptDidLoad:(NSNotification *)notification
162162
{
163+
RCTAssertMainThread();
163164
RCTBridge *bridge = notification.userInfo[@"bridge"];
164-
dispatch_async(dispatch_get_main_queue(), ^{
165-
[self bundleFinishedLoading:bridge];
166-
});
165+
[self bundleFinishedLoading:bridge];
167166
}
168167

169168
- (void)bundleFinishedLoading:(RCTBridge *)bridge

React/Executors/RCTContextExecutor.m

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,14 +458,15 @@ - (void)executeApplicationScript:(NSString *)script
458458
if (!strongSelf || !strongSelf.isValid) {
459459
return;
460460
}
461-
RCTPerformanceLoggerStart(RCTPLAppScriptExecution);
461+
462+
RCTPerformanceLoggerStart(RCTPLScriptExecution);
462463
JSValueRef jsError = NULL;
463464
JSStringRef execJSString = JSStringCreateWithCFString((__bridge CFStringRef)script);
464465
JSStringRef jsURL = JSStringCreateWithCFString((__bridge CFStringRef)sourceURL.absoluteString);
465466
JSValueRef result = JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, &jsError);
466467
JSStringRelease(jsURL);
467468
JSStringRelease(execJSString);
468-
RCTPerformanceLoggerEnd(RCTPLAppScriptExecution);
469+
RCTPerformanceLoggerEnd(RCTPLScriptExecution);
469470

470471
if (onComplete) {
471472
NSError *error;

0 commit comments

Comments
 (0)