mirror of
https://github.com/status-im/react-native.git
synced 2025-01-14 03:26:07 +00:00
De-batch native->js calls and react updates
Summary: @public Take a step back and de-batch the bridge calls so we can have better profiling data and a better starting point to work on future optimisations. Also gave a 10~15% win on first render. Reviewed By: @javache Differential Revision: D2493674 fb-gh-sync-id: 05165fdd00645bdf43e844bb0c4300a2f63e7038
This commit is contained in:
parent
261100d9d0
commit
baf5b7b4d5
@ -62,9 +62,11 @@
|
||||
RCT_TEST(IntegrationTestHarnessTest)
|
||||
RCT_TEST(TimersTest)
|
||||
RCT_TEST(AsyncStorageTest)
|
||||
RCT_TEST(LayoutEventsTest)
|
||||
RCT_TEST(AppEventsTest)
|
||||
RCT_TEST(SimpleSnapshotTest)
|
||||
RCT_TEST(PromiseTest)
|
||||
|
||||
// Disable due to flakiness: #8686784
|
||||
//RCT_TEST(LayoutEventsTest)
|
||||
//RCT_TEST(PromiseTest)
|
||||
|
||||
@end
|
||||
|
@ -55,7 +55,6 @@ class MessageQueue {
|
||||
this._callbackID = 0;
|
||||
|
||||
[
|
||||
'processBatch',
|
||||
'invokeCallbackAndReturnFlushedQueue',
|
||||
'callFunctionReturnFlushedQueue',
|
||||
'flushedQueue',
|
||||
@ -75,42 +74,30 @@ class MessageQueue {
|
||||
/**
|
||||
* Public APIs
|
||||
*/
|
||||
processBatch(batch) {
|
||||
callFunctionReturnFlushedQueue(module, method, args) {
|
||||
guard(() => {
|
||||
ReactUpdates.batchedUpdates(() => {
|
||||
batch.forEach((call) => {
|
||||
let method = call.method === 'callFunctionReturnFlushedQueue' ?
|
||||
'__callFunction' : '__invokeCallback';
|
||||
guard(() => this[method].apply(this, call.args));
|
||||
});
|
||||
|
||||
this.__callImmediates();
|
||||
});
|
||||
|
||||
// batchedUpdates might still trigger setImmediates
|
||||
while (JSTimersExecution.immediates.length) {
|
||||
ReactUpdates.batchedUpdates(() => {
|
||||
this.__callImmediates();
|
||||
});
|
||||
}
|
||||
this.__callFunction(module, method, args);
|
||||
this.__callImmediates();
|
||||
});
|
||||
|
||||
return this.__flushedQueue();
|
||||
}
|
||||
|
||||
callFunctionReturnFlushedQueue(module, method, args) {
|
||||
guard(() => this.__callFunction(module, method, args));
|
||||
return this.flushedQueue();
|
||||
}
|
||||
|
||||
invokeCallbackAndReturnFlushedQueue(cbID, args) {
|
||||
guard(() => this.__invokeCallback(cbID, args));
|
||||
guard(() => {
|
||||
this.__invokeCallback(cbID, args);
|
||||
this.__callImmediates();
|
||||
});
|
||||
|
||||
return this.flushedQueue();
|
||||
}
|
||||
|
||||
flushedQueue() {
|
||||
this.__callImmediates();
|
||||
return this.__flushedQueue();
|
||||
|
||||
let queue = this._queue;
|
||||
this._queue = [[],[],[]];
|
||||
return queue[0].length ? queue : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,11 +110,6 @@ class MessageQueue {
|
||||
BridgeProfiling.profileEnd();
|
||||
}
|
||||
|
||||
__flushedQueue() {
|
||||
let queue = this._queue;
|
||||
this._queue = [[],[],[]];
|
||||
return queue[0].length ? queue : null;
|
||||
}
|
||||
__nativeCall(module, method, params, onFail, onSucc) {
|
||||
if (onFail || onSucc) {
|
||||
// eventually delete old debug info
|
||||
|
@ -95,29 +95,6 @@ describe('MessageQueue', () => {
|
||||
queue.__invokeCallback(1);
|
||||
expect(() => queue.__invokeCallback(0)).toThrow();
|
||||
});
|
||||
|
||||
describe('processBatch', () => {
|
||||
|
||||
it('should call __invokeCallback for invokeCallbackAndReturnFlushedQueue', () => {
|
||||
queue.__invokeCallback = jasmine.createSpy();
|
||||
queue.processBatch([{
|
||||
method: 'invokeCallbackAndReturnFlushedQueue',
|
||||
args: [],
|
||||
}]);
|
||||
expect(queue.__invokeCallback.callCount).toEqual(1);
|
||||
});
|
||||
|
||||
it('should call __callFunction for callFunctionReturnFlushedQueue', () => {
|
||||
queue.__callFunction = jasmine.createSpy();
|
||||
queue.processBatch([{
|
||||
method: 'callFunctionReturnFlushedQueue',
|
||||
args: [],
|
||||
}]);
|
||||
expect(queue.__callFunction.callCount).toEqual(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
var remoteModulesConfig = {
|
||||
|
@ -69,8 +69,6 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
|
||||
CADisplayLink *_mainDisplayLink;
|
||||
CADisplayLink *_jsDisplayLink;
|
||||
NSMutableSet *_frameUpdateObservers;
|
||||
NSMutableArray *_scheduledCalls;
|
||||
RCTSparseArray *_scheduledCallbacks;
|
||||
}
|
||||
|
||||
- (instancetype)initWithParentBridge:(RCTBridge *)bridge
|
||||
@ -91,8 +89,6 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
|
||||
_loading = YES;
|
||||
_moduleDataByID = [NSMutableArray new];
|
||||
_frameUpdateObservers = [NSMutableSet new];
|
||||
_scheduledCalls = [NSMutableArray new];
|
||||
_scheduledCallbacks = [RCTSparseArray new];
|
||||
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
|
||||
|
||||
if (RCT_DEV) {
|
||||
@ -334,14 +330,12 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
|
||||
{
|
||||
RCTAssertJSThread();
|
||||
|
||||
BOOL pauseDisplayLink = ![_scheduledCallbacks count] && ![_scheduledCalls count];
|
||||
if (pauseDisplayLink) {
|
||||
for (RCTModuleData *moduleData in _frameUpdateObservers) {
|
||||
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
||||
if (!observer.paused) {
|
||||
pauseDisplayLink = NO;
|
||||
break;
|
||||
}
|
||||
BOOL pauseDisplayLink = YES;
|
||||
for (RCTModuleData *moduleData in _frameUpdateObservers) {
|
||||
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
||||
if (!observer.paused) {
|
||||
pauseDisplayLink = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_jsDisplayLink.paused = pauseDisplayLink;
|
||||
@ -631,28 +625,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||
RCTProfileBeginEvent(0, @"enqueue_call", nil);
|
||||
|
||||
RCTBatchedBridge *strongSelf = weakSelf;
|
||||
if (!strongSelf.isValid || !strongSelf->_scheduledCallbacks || !strongSelf->_scheduledCalls) {
|
||||
return;
|
||||
}
|
||||
|
||||
[strongSelf _actuallyInvokeAndProcessModule:module method:method arguments:args];
|
||||
|
||||
RCT_IF_DEV(NSNumber *callID = _RCTProfileBeginFlowEvent();)
|
||||
id call = @{
|
||||
@"js_args": @{
|
||||
@"module": module,
|
||||
@"method": method,
|
||||
@"args": args,
|
||||
},
|
||||
RCT_IF_DEV(@"call_id": callID,)
|
||||
};
|
||||
if ([method isEqualToString:@"invokeCallbackAndReturnFlushedQueue"]) {
|
||||
strongSelf->_scheduledCallbacks[args[0]] = call;
|
||||
} else {
|
||||
[strongSelf->_scheduledCalls addObject:call];
|
||||
}
|
||||
[strongSelf updateJSDisplayLinkState];
|
||||
|
||||
RCTProfileEndEvent(0, @"objc_call", call);
|
||||
}];
|
||||
}
|
||||
|
||||
@ -848,24 +823,10 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
||||
}
|
||||
}
|
||||
|
||||
NSArray *calls = [_scheduledCallbacks.allObjects arrayByAddingObjectsFromArray:_scheduledCalls];
|
||||
[self updateJSDisplayLinkState];
|
||||
|
||||
RCT_IF_DEV(
|
||||
RCTProfileImmediateEvent(0, @"JS Thread Tick", 'g');
|
||||
|
||||
for (NSDictionary *call in calls) {
|
||||
_RCTProfileEndFlowEvent(call[@"call_id"]);
|
||||
}
|
||||
)
|
||||
|
||||
if (calls.count > 0) {
|
||||
_scheduledCalls = [NSMutableArray new];
|
||||
_scheduledCallbacks = [RCTSparseArray new];
|
||||
[self _actuallyInvokeAndProcessModule:@"BatchedBridge"
|
||||
method:@"processBatch"
|
||||
arguments:@[[calls valueForKey:@"js_args"]]];
|
||||
[self updateJSDisplayLinkState];
|
||||
}
|
||||
RCTProfileImmediateEvent(0, @"JS Thread Tick", 'g');
|
||||
|
||||
RCTProfileEndEvent(0, @"objc_call", nil);
|
||||
|
||||
|
@ -469,7 +469,7 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
|
||||
}
|
||||
}
|
||||
|
||||
if (!resultJSRef) {
|
||||
if (errorJSRef) {
|
||||
onComplete(nil, RCTNSErrorFromJSError(contextJSRef, errorJSRef));
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user