From c25c98c00c8c195f85c9fb17eae3cb0c36b465f5 Mon Sep 17 00:00:00 2001 From: Justin Spahr-Summers Date: Wed, 2 Dec 2015 05:12:17 -0800 Subject: [PATCH] Flush UI blocks as soon as they're accumulated Summary: public Currently, we wait to invoke `-flushUIBlocks` until the JavaScript batch to native has completed. This means we may be waiting an unnecessarily long time to perform view hierarchy changes and prop changes. By instead invoking this after each chunk of enqueued UI blocks, we can perform some updates more eagerly, increasing our utilization of the main thread while splitting up the amount of time we spend running upon it. This shouldn't affect layout, which is still tied to `-batchDidComplete`, so any visual inconsistencies should be limited to prop changes, which seems acceptable for the dramatic improvement in performance. Reviewed By: javache Differential Revision: D2658552 fb-gh-sync-id: 6d4560e21d7da1b02d2f30d1860d60735f11c4b5 --- React/Base/RCTBatchedBridge.m | 12 ++++++++++++ React/Base/RCTBridgeModule.h | 8 ++++++++ React/Modules/RCTUIManager.h | 11 +++++++++++ React/Modules/RCTUIManager.m | 7 +++++++ 4 files changed, 38 insertions(+) diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 8923d85ef..bbb8fe24a 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -720,6 +720,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR if (buffer != nil && buffer != (id)kCFNull) { _wasBatchActive = YES; [self handleBuffer:buffer]; + [self partialBatchDidFlush]; } if (batchEnded) { @@ -800,6 +801,17 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR } } +- (void)partialBatchDidFlush +{ + for (RCTModuleData *moduleData in _moduleDataByID) { + if (moduleData.hasInstance && [moduleData.instance respondsToSelector:@selector(partialBatchDidFlush)]) { + [self dispatchBlock:^{ + [moduleData.instance partialBatchDidFlush]; + } queue:moduleData.methodQueue]; + } + } +} + - (void)batchDidComplete { // TODO: batchDidComplete is only used by RCTUIManager - can we eliminate this special case? diff --git a/React/Base/RCTBridgeModule.h b/React/Base/RCTBridgeModule.h index 436b26c80..dd6dda34c 100644 --- a/React/Base/RCTBridgeModule.h +++ b/React/Base/RCTBridgeModule.h @@ -235,4 +235,12 @@ RCT_EXTERN void RCTRegisterModule(Class); \ */ - (void)batchDidComplete; +/** + * Notifies the module that the active batch of JS method invocations has been + * partially flushed. + * + * This occurs before -batchDidComplete, and more frequently. + */ +- (void)partialBatchDidFlush; + @end diff --git a/React/Modules/RCTUIManager.h b/React/Modules/RCTUIManager.h index daaf40ac2..dc0bcd9d9 100644 --- a/React/Modules/RCTUIManager.h +++ b/React/Modules/RCTUIManager.h @@ -77,6 +77,17 @@ RCT_EXTERN NSString *const RCTUIManagerRootViewKey; */ + (UIView *)JSResponder; +/** + * Normally, UI changes are not applied until the complete batch of method + * invocations from JavaScript to native has completed. + * + * Setting this to YES will flush UI changes sooner, which could potentially + * result in inconsistent UI updates. + * + * The default is NO (recommended). + */ +@property (atomic, assign) BOOL unsafeFlushUIChangesBeforeBatchEnds; + @end /** diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index e4f569e5e..c3c1ea589 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -880,6 +880,13 @@ RCT_EXPORT_METHOD(findSubviewIn:(nonnull NSNumber *)reactTag atPoint:(CGPoint)po }]; } +- (void)partialBatchDidFlush +{ + if (self.unsafeFlushUIChangesBeforeBatchEnds) { + [self flushUIBlocks]; + } +} + - (void)batchDidComplete { // Gather blocks to be executed now that all view hierarchy manipulations have