From 529687f9234ae9730a2660a1fee10ce45319c3fb Mon Sep 17 00:00:00 2001 From: Tadeu Zagallo Date: Wed, 14 Oct 2015 09:48:00 -0700 Subject: [PATCH] Defer calls until bridge finishes loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: @​public When de-batching the calls from native -> JS, some calls were being dispatched before the bridge had finished loading, which would cause lost calls when running on the `ContextExecutor` and redbox when running in the Chrome debugger Reviewed By: @javache Differential Revision: D2540746 fb-gh-sync-id: ece29406648d3cbcb42cef3b32b8774ff0c15fd8 --- React/Base/RCTBatchedBridge.m | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 584d8e1d5..b0cc0f0de 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -64,6 +64,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); BOOL _loading; BOOL _valid; __weak id _javaScriptExecutor; + NSMutableArray *_pendingCalls; NSMutableArray *_moduleDataByID; RCTModuleMap *_modulesByName; CADisplayLink *_mainDisplayLink; @@ -87,6 +88,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); */ _valid = YES; _loading = YES; + _pendingCalls = [NSMutableArray new]; _moduleDataByID = [NSMutableArray new]; _frameUpdateObservers = [NSMutableSet new]; _jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)]; @@ -212,7 +214,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); } else { // Allow testing without a script dispatch_async(dispatch_get_main_queue(), ^{ - _loading = NO; + [self didFinishLoading]; [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification object:_parentBridge userInfo:@{ @"bridge": self }]; @@ -382,7 +384,7 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); // Perform the state update and notification on the main thread, so we can't run into // timing issues with RCTRootView dispatch_async(dispatch_get_main_queue(), ^{ - _loading = NO; + [self didFinishLoading]; [[NSNotificationCenter defaultCenter] postNotificationName:RCTJavaScriptDidLoadNotification object:_parentBridge userInfo:@{ @"bridge": self }]; @@ -390,6 +392,18 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void); }]; } +- (void)didFinishLoading +{ + _loading = NO; + [_javaScriptExecutor executeBlockOnJavaScriptQueue:^{ + for (NSArray *call in _pendingCalls) { + [self _actuallyInvokeAndProcessModule:call[0] + method:call[1] + arguments:call[2]]; + } + }]; +} + - (void)stopLoadingWithError:(NSError *)error { RCTAssertMainThread(); @@ -625,9 +639,15 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR RCTProfileBeginEvent(0, @"enqueue_call", nil); RCTBatchedBridge *strongSelf = weakSelf; + if (!strongSelf || !strongSelf.valid) { + return; + } - [strongSelf _actuallyInvokeAndProcessModule:module method:method arguments:args]; - + if (strongSelf.loading) { + [strongSelf->_pendingCalls addObject:@[module, method, args]]; + } else { + [strongSelf _actuallyInvokeAndProcessModule:module method:method arguments:args]; + } }]; }