Reduced work done on main thread by RCTImageLoader

Summary: public

Removed redundant calls to [RCTNetwork canHandleRequest] in release mode when loading images, and improved perf for handler lookups when running in debug mode.

Reviewed By: tadeuzagallo

Differential Revision: D2663307

fb-gh-sync-id: 13285154c1c3773b32dba7894d86d14992e2fd7d
This commit is contained in:
Nick Lockwood 2015-11-17 07:18:55 -08:00 committed by facebook-github-bot-0
parent c043c68e7e
commit 5b796cec34
4 changed files with 126 additions and 102 deletions

View File

@ -99,8 +99,11 @@ RCT_EXPORT_MODULE()
float previousPriority = 0;
id<RCTImageURLLoader> previousLoader = nil;
for (id<RCTImageURLLoader> loader in _loaders) {
if ([loader canLoadImageURL:URL]) {
float priority = [loader respondsToSelector:@selector(loaderPriority)] ? [loader loaderPriority] : 0;
if (previousLoader && priority < previousPriority) {
return previousLoader;
}
if ([loader canLoadImageURL:URL]) {
if (previousLoader) {
if (priority == previousPriority) {
RCTLogError(@"The RCTImageURLLoaders %@ and %@ both reported that"
@ -114,6 +117,7 @@ RCT_EXPORT_MODULE()
}
}
}
return previousLoader;
}
// Normal code path
@ -132,8 +136,11 @@ RCT_EXPORT_MODULE()
float previousPriority = 0;
id<RCTImageDataDecoder> previousDecoder = nil;
for (id<RCTImageDataDecoder> decoder in _decoders) {
if ([decoder canDecodeImageData:data]) {
float priority = [decoder respondsToSelector:@selector(decoderPriority)] ? [decoder decoderPriority] : 0;
if (previousDecoder && priority < previousPriority) {
return previousDecoder;
}
if ([decoder canDecodeImageData:data]) {
if (previousDecoder) {
if (priority == previousPriority) {
RCTLogError(@"The RCTImageDataDecoders %@ and %@ both reported that"
@ -148,6 +155,7 @@ RCT_EXPORT_MODULE()
}
}
}
return previousDecoder;
}
// Normal code path
@ -211,16 +219,20 @@ RCT_EXPORT_MODULE()
}
// Check if networking module is available
if (![_bridge respondsToSelector:@selector(networking)]) {
if (RCT_DEBUG && ![_bridge respondsToSelector:@selector(networking)]) {
RCTLogError(@"No suitable image URL loader found for %@. You may need to "
" import the RCTNetworking library in order to load images.",
imageTag);
return ^{};
}
// Use networking module to load image
if ([_bridge.networking canHandleRequest:request]) {
// Check if networking module can load image
if (RCT_DEBUG && ![_bridge.networking canHandleRequest:request]) {
RCTLogError(@"No suitable image URL loader found for %@", imageTag);
return ^{};
}
// Use networking module to load image
__weak RCTImageLoader *weakSelf = self;
__block RCTImageLoaderCancellationBlock decodeCancel = nil;
RCTURLRequestCompletionBlock processResponse =
@ -304,16 +316,17 @@ RCT_EXPORT_MODULE()
};
}
RCTLogError(@"No suitable image URL loader found for %@", imageTag);
return ^{};
}
- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(UIViewContentMode)resizeMode
completionBlock:(RCTImageLoaderCompletionBlock)completionHandler
{
if (data.length == 0) {
completionHandler(RCTErrorWithMessage(@"No image data"), nil);
return ^{};
}
id<RCTImageDataDecoder> imageDecoder = [self imageDataDecoderForData:data];
if (imageDecoder) {

View File

@ -183,13 +183,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
resizeMode:self.contentMode
progressBlock:progressHandler
completionBlock:^(NSError *error, UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^{
if (image.reactKeyframeAnimation) {
[self.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"];
} else {
[self.layer removeAnimationForKey:@"contents"];
self.image = image;
}
if (error) {
if (_onError) {
_onError(@{ @"error": error.localizedDescription });
@ -202,6 +195,14 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
if (_onLoadEnd) {
_onLoadEnd(nil);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (image.reactKeyframeAnimation) {
[self.layer addAnimation:image.reactKeyframeAnimation forKey:@"contents"];
} else {
[self.layer removeAnimationForKey:@"contents"];
self.image = image;
}
});
}];
} else {

View File

@ -165,8 +165,11 @@ RCT_EXPORT_MODULE()
float previousPriority = 0;
id<RCTURLRequestHandler> previousHandler = nil;
for (id<RCTURLRequestHandler> handler in _handlers) {
if ([handler canHandleRequest:request]) {
float priority = [handler respondsToSelector:@selector(handlerPriority)] ? [handler handlerPriority] : 0;
if (previousHandler && priority < previousPriority) {
return previousHandler;
}
if ([handler canHandleRequest:request]) {
if (previousHandler) {
if (priority == previousPriority) {
RCTLogError(@"The RCTURLRequestHandlers %@ and %@ both reported that"
@ -180,6 +183,7 @@ RCT_EXPORT_MODULE()
}
}
}
return previousHandler;
}
// Normal code path

View File

@ -79,6 +79,12 @@ typedef void (^RCTFatalHandler)(NSError *error);
#define RCTAssertMainThread() RCTAssert([NSThread isMainThread], \
@"This function must be called on the main thread")
/**
* Convenience macro for asserting that we're running off the main thread.
*/
#define RCTAssertNotMainThread() RCTAssert(![NSThread isMainThread], \
@"This function must not be called on the main thread")
/**
* These methods get and set the current assert function called by the RCTAssert
* macros. You can use these to replace the standard behavior with custom assert