[ReactNative] Batch JS -> Native calls per queue
Summary: @public For every call that comes from JS to Native we'd call dispatch_async so the method would be cllead on the queue/thread it's expecting. This diff buckets the calls by target queue, dispatches only once to that queue, and then call all the methods for it inside the same dispatch. Test Plan: {F22510090}
This commit is contained in:
parent
459882ea7e
commit
2a08897c6e
|
@ -1379,15 +1379,42 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: if we sort the requests by module, we could dispatch once per
|
||||
// module instead of per request, which would reduce the call overhead.
|
||||
NSMapTable *buckets = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsStrongMemory capacity:_queuesByID.count];
|
||||
for (NSUInteger i = 0; i < numRequests; i++) {
|
||||
@autoreleasepool {
|
||||
[self _handleRequestNumber:i
|
||||
moduleID:[moduleIDs[i] integerValue]
|
||||
methodID:[methodIDs[i] integerValue]
|
||||
params:paramsArrays[i]
|
||||
context:context];
|
||||
id queue = RCTNullIfNil(_queuesByID[moduleIDs[i]]);
|
||||
NSMutableOrderedSet *set = [buckets objectForKey:queue];
|
||||
if (!set) {
|
||||
set = [[NSMutableOrderedSet alloc] init];
|
||||
[buckets setObject:set forKey:queue];
|
||||
}
|
||||
[set addObject:@(i)];
|
||||
}
|
||||
|
||||
for (id queue in buckets) {
|
||||
RCTProfileBeginFlowEvent();
|
||||
dispatch_block_t block = ^{
|
||||
RCTProfileEndFlowEvent();
|
||||
RCTProfileBeginEvent();
|
||||
|
||||
NSOrderedSet *calls = [buckets objectForKey:queue];
|
||||
@autoreleasepool {
|
||||
for (NSNumber *indexObj in calls) {
|
||||
NSUInteger index = indexObj.unsignedIntegerValue;
|
||||
[self _handleRequestNumber:index
|
||||
moduleID:[moduleIDs[index] integerValue]
|
||||
methodID:[methodIDs[index] integerValue]
|
||||
params:paramsArrays[index]
|
||||
context:context];
|
||||
}
|
||||
}
|
||||
|
||||
RCTProfileEndEvent(RCTCurrentThreadName(), @"objc_call,dispatch_async", @{ @"calls": @(calls.count) });
|
||||
};
|
||||
|
||||
if (queue == (id)kCFNull) {
|
||||
[_javaScriptExecutor executeBlockOnJavaScriptQueue:block];
|
||||
} else {
|
||||
dispatch_async(queue, block);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1407,8 +1434,6 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||
params:(NSArray *)params
|
||||
context:(NSNumber *)context
|
||||
{
|
||||
RCTAssertJSThread();
|
||||
|
||||
if (!self.isValid) {
|
||||
return NO;
|
||||
}
|
||||
|
@ -1426,6 +1451,8 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||
return NO;
|
||||
}
|
||||
|
||||
RCTProfileBeginEvent();
|
||||
|
||||
RCTModuleMethod *method = methods[methodID];
|
||||
|
||||
// Look up module
|
||||
|
@ -1435,36 +1462,22 @@ RCT_INNER_BRIDGE_ONLY(_invokeAndProcessModule:(NSString *)module method:(NSStrin
|
|||
return NO;
|
||||
}
|
||||
|
||||
RCTProfileBeginFlowEvent();
|
||||
__weak RCTBatchedBridge *weakSelf = self;
|
||||
[self dispatchBlock:^{
|
||||
RCTProfileEndFlowEvent();
|
||||
RCTProfileBeginEvent();
|
||||
RCTBatchedBridge *strongSelf = weakSelf;
|
||||
|
||||
if (!strongSelf.isValid) {
|
||||
// strongSelf has been invalidated since the dispatch_async call and this
|
||||
// invocation should not continue.
|
||||
return;
|
||||
@try {
|
||||
[method invokeWithBridge:self module:module arguments:params context:context];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
RCTLogError(@"Exception thrown while invoking %@ on target %@ with params %@: %@", method.JSMethodName, module, params, exception);
|
||||
if (!RCT_DEBUG && [exception.name rangeOfString:@"Unhandled JS Exception"].location != NSNotFound) {
|
||||
@throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
@try {
|
||||
[method invokeWithBridge:strongSelf module:module arguments:params context:context];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
RCTLogError(@"Exception thrown while invoking %@ on target %@ with params %@: %@", method.JSMethodName, module, params, exception);
|
||||
if (!RCT_DEBUG && [exception.name rangeOfString:@"Unhandled JS Exception"].location != NSNotFound) {
|
||||
@throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
RCTProfileEndEvent(@"Invoke callback", @"objc_call", @{
|
||||
@"module": method.moduleClassName,
|
||||
@"method": method.JSMethodName,
|
||||
@"selector": NSStringFromSelector(method.selector),
|
||||
@"args": RCTJSONStringify(params ?: [NSNull null], NULL),
|
||||
});
|
||||
} forModuleID:@(moduleID)];
|
||||
RCTProfileEndEvent(@"Invoke callback", @"objc_call", @{
|
||||
@"module": method.moduleClassName,
|
||||
@"method": method.JSMethodName,
|
||||
@"selector": NSStringFromSelector(method.selector),
|
||||
@"args": RCTJSONStringify(params ?: [NSNull null], NULL),
|
||||
});
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
|
|
@ -57,3 +57,6 @@ RCT_EXTERN BOOL RCTRunningInTestEnvironment(void);
|
|||
|
||||
// Return YES if image has an alpha component
|
||||
RCT_EXTERN BOOL RCTImageHasAlpha(CGImageRef image);
|
||||
|
||||
RCT_EXTERN id RCTNullIfNil(id value);
|
||||
RCT_EXTERN id RCTNilIfNull(id value);
|
||||
|
|
|
@ -281,3 +281,13 @@ BOOL RCTImageHasAlpha(CGImageRef image)
|
|||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
id RCTNullIfNil(id value)
|
||||
{
|
||||
return value ?: (id)kCFNull;
|
||||
}
|
||||
|
||||
id RCTNilIfNull(id value)
|
||||
{
|
||||
return value == (id)kCFNull ? nil : value;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue