mirror of
https://github.com/status-im/react-native.git
synced 2025-01-14 11:34:23 +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(IntegrationTestHarnessTest)
|
||||||
RCT_TEST(TimersTest)
|
RCT_TEST(TimersTest)
|
||||||
RCT_TEST(AsyncStorageTest)
|
RCT_TEST(AsyncStorageTest)
|
||||||
RCT_TEST(LayoutEventsTest)
|
|
||||||
RCT_TEST(AppEventsTest)
|
RCT_TEST(AppEventsTest)
|
||||||
RCT_TEST(SimpleSnapshotTest)
|
RCT_TEST(SimpleSnapshotTest)
|
||||||
RCT_TEST(PromiseTest)
|
|
||||||
|
// Disable due to flakiness: #8686784
|
||||||
|
//RCT_TEST(LayoutEventsTest)
|
||||||
|
//RCT_TEST(PromiseTest)
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -55,7 +55,6 @@ class MessageQueue {
|
|||||||
this._callbackID = 0;
|
this._callbackID = 0;
|
||||||
|
|
||||||
[
|
[
|
||||||
'processBatch',
|
|
||||||
'invokeCallbackAndReturnFlushedQueue',
|
'invokeCallbackAndReturnFlushedQueue',
|
||||||
'callFunctionReturnFlushedQueue',
|
'callFunctionReturnFlushedQueue',
|
||||||
'flushedQueue',
|
'flushedQueue',
|
||||||
@ -75,42 +74,30 @@ class MessageQueue {
|
|||||||
/**
|
/**
|
||||||
* Public APIs
|
* Public APIs
|
||||||
*/
|
*/
|
||||||
processBatch(batch) {
|
callFunctionReturnFlushedQueue(module, method, args) {
|
||||||
guard(() => {
|
guard(() => {
|
||||||
ReactUpdates.batchedUpdates(() => {
|
this.__callFunction(module, method, args);
|
||||||
batch.forEach((call) => {
|
this.__callImmediates();
|
||||||
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();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.__flushedQueue();
|
|
||||||
}
|
|
||||||
|
|
||||||
callFunctionReturnFlushedQueue(module, method, args) {
|
|
||||||
guard(() => this.__callFunction(module, method, args));
|
|
||||||
return this.flushedQueue();
|
return this.flushedQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeCallbackAndReturnFlushedQueue(cbID, args) {
|
invokeCallbackAndReturnFlushedQueue(cbID, args) {
|
||||||
guard(() => this.__invokeCallback(cbID, args));
|
guard(() => {
|
||||||
|
this.__invokeCallback(cbID, args);
|
||||||
|
this.__callImmediates();
|
||||||
|
});
|
||||||
|
|
||||||
return this.flushedQueue();
|
return this.flushedQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
flushedQueue() {
|
flushedQueue() {
|
||||||
this.__callImmediates();
|
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();
|
BridgeProfiling.profileEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
__flushedQueue() {
|
|
||||||
let queue = this._queue;
|
|
||||||
this._queue = [[],[],[]];
|
|
||||||
return queue[0].length ? queue : null;
|
|
||||||
}
|
|
||||||
__nativeCall(module, method, params, onFail, onSucc) {
|
__nativeCall(module, method, params, onFail, onSucc) {
|
||||||
if (onFail || onSucc) {
|
if (onFail || onSucc) {
|
||||||
// eventually delete old debug info
|
// eventually delete old debug info
|
||||||
|
@ -95,29 +95,6 @@ describe('MessageQueue', () => {
|
|||||||
queue.__invokeCallback(1);
|
queue.__invokeCallback(1);
|
||||||
expect(() => queue.__invokeCallback(0)).toThrow();
|
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 = {
|
var remoteModulesConfig = {
|
||||||
|
@ -69,8 +69,6 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
|
|||||||
CADisplayLink *_mainDisplayLink;
|
CADisplayLink *_mainDisplayLink;
|
||||||
CADisplayLink *_jsDisplayLink;
|
CADisplayLink *_jsDisplayLink;
|
||||||
NSMutableSet *_frameUpdateObservers;
|
NSMutableSet *_frameUpdateObservers;
|
||||||
NSMutableArray *_scheduledCalls;
|
|
||||||
RCTSparseArray *_scheduledCallbacks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithParentBridge:(RCTBridge *)bridge
|
- (instancetype)initWithParentBridge:(RCTBridge *)bridge
|
||||||
@ -91,8 +89,6 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
|
|||||||
_loading = YES;
|
_loading = YES;
|
||||||
_moduleDataByID = [NSMutableArray new];
|
_moduleDataByID = [NSMutableArray new];
|
||||||
_frameUpdateObservers = [NSMutableSet new];
|
_frameUpdateObservers = [NSMutableSet new];
|
||||||
_scheduledCalls = [NSMutableArray new];
|
|
||||||
_scheduledCallbacks = [RCTSparseArray new];
|
|
||||||
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
|
_jsDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_jsThreadUpdate:)];
|
||||||
|
|
||||||
if (RCT_DEV) {
|
if (RCT_DEV) {
|
||||||
@ -334,14 +330,12 @@ RCT_EXTERN NSArray *RCTGetModuleClasses(void);
|
|||||||
{
|
{
|
||||||
RCTAssertJSThread();
|
RCTAssertJSThread();
|
||||||
|
|
||||||
BOOL pauseDisplayLink = ![_scheduledCallbacks count] && ![_scheduledCalls count];
|
BOOL pauseDisplayLink = YES;
|
||||||
if (pauseDisplayLink) {
|
for (RCTModuleData *moduleData in _frameUpdateObservers) {
|
||||||
for (RCTModuleData *moduleData in _frameUpdateObservers) {
|
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
||||||
id<RCTFrameUpdateObserver> observer = (id<RCTFrameUpdateObserver>)moduleData.instance;
|
if (!observer.paused) {
|
||||||
if (!observer.paused) {
|
pauseDisplayLink = NO;
|
||||||
pauseDisplayLink = NO;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_jsDisplayLink.paused = pauseDisplayLink;
|
_jsDisplayLink.paused = pauseDisplayLink;
|
||||||
@ -631,28 +625,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
|
|||||||
RCTProfileBeginEvent(0, @"enqueue_call", nil);
|
RCTProfileBeginEvent(0, @"enqueue_call", nil);
|
||||||
|
|
||||||
RCTBatchedBridge *strongSelf = weakSelf;
|
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) {
|
RCTProfileImmediateEvent(0, @"JS Thread Tick", 'g');
|
||||||
_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];
|
|
||||||
}
|
|
||||||
|
|
||||||
RCTProfileEndEvent(0, @"objc_call", nil);
|
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));
|
onComplete(nil, RCTNSErrorFromJSError(contextJSRef, errorJSRef));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user