mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-25 12:55:41 +08:00
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:
committed by
facebook-github-bot-0
parent
c043c68e7e
commit
5b796cec34
@@ -99,8 +99,11 @@ RCT_EXPORT_MODULE()
|
||||
float previousPriority = 0;
|
||||
id<RCTImageURLLoader> previousLoader = nil;
|
||||
for (id<RCTImageURLLoader> loader in _loaders) {
|
||||
float priority = [loader respondsToSelector:@selector(loaderPriority)] ? [loader loaderPriority] : 0;
|
||||
if (previousLoader && priority < previousPriority) {
|
||||
return previousLoader;
|
||||
}
|
||||
if ([loader canLoadImageURL:URL]) {
|
||||
float priority = [loader respondsToSelector:@selector(loaderPriority)] ? [loader loaderPriority] : 0;
|
||||
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) {
|
||||
float priority = [decoder respondsToSelector:@selector(decoderPriority)] ? [decoder decoderPriority] : 0;
|
||||
if (previousDecoder && priority < previousPriority) {
|
||||
return previousDecoder;
|
||||
}
|
||||
if ([decoder canDecodeImageData:data]) {
|
||||
float priority = [decoder respondsToSelector:@selector(decoderPriority)] ? [decoder decoderPriority] : 0;
|
||||
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,101 +219,101 @@ 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]) {
|
||||
|
||||
__weak RCTImageLoader *weakSelf = self;
|
||||
__block RCTImageLoaderCancellationBlock decodeCancel = nil;
|
||||
RCTURLRequestCompletionBlock processResponse =
|
||||
^(NSURLResponse *response, NSData *data, NSError *error) {
|
||||
|
||||
// Check for system errors
|
||||
if (error) {
|
||||
completionHandler(error, nil);
|
||||
return;
|
||||
} else if (!data) {
|
||||
completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for http errors
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
|
||||
if (statusCode != 200) {
|
||||
completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain
|
||||
code:statusCode
|
||||
userInfo:nil], nil);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode image
|
||||
decodeCancel = [weakSelf decodeImageData:data
|
||||
size:size
|
||||
scale:scale
|
||||
resizeMode:resizeMode
|
||||
completionBlock:completionHandler];
|
||||
};
|
||||
|
||||
// Check for cached response before reloading
|
||||
// TODO: move URL cache out of RCTImageLoader into its own module
|
||||
NSCachedURLResponse *cachedResponse = [_cache cachedResponseForRequest:request];
|
||||
if (cachedResponse) {
|
||||
processResponse(cachedResponse.response, cachedResponse.data, nil);
|
||||
return ^{};
|
||||
}
|
||||
|
||||
// Add missing png extension
|
||||
if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
|
||||
NSMutableURLRequest *mutableRequest = [request mutableCopy];
|
||||
mutableRequest.URL = [NSURL fileURLWithPath:[request.URL.path stringByAppendingPathExtension:@"png"]];
|
||||
request = mutableRequest;
|
||||
}
|
||||
|
||||
// Download image
|
||||
RCTNetworkTask *task = [_bridge.networking networkTaskWithRequest:request completionBlock:
|
||||
^(NSURLResponse *response, NSData *data, NSError *error) {
|
||||
if (error) {
|
||||
completionHandler(error, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the response
|
||||
// TODO: move URL cache out of RCTImageLoader into its own module
|
||||
RCTImageLoader *strongSelf = weakSelf;
|
||||
BOOL isHTTPRequest = [request.URL.scheme hasPrefix:@"http"];
|
||||
[strongSelf->_cache storeCachedResponse:
|
||||
[[NSCachedURLResponse alloc] initWithResponse:response
|
||||
data:data
|
||||
userInfo:nil
|
||||
storagePolicy:isHTTPRequest ? NSURLCacheStorageAllowed: NSURLCacheStorageAllowedInMemoryOnly]
|
||||
forRequest:request];
|
||||
|
||||
// Process image data
|
||||
processResponse(response, data, nil);
|
||||
|
||||
}];
|
||||
task.downloadProgressBlock = progressHandler;
|
||||
[task start];
|
||||
|
||||
return ^{
|
||||
[task cancel];
|
||||
if (decodeCancel) {
|
||||
decodeCancel();
|
||||
}
|
||||
OSAtomicOr32Barrier(1, &cancelled);
|
||||
};
|
||||
// Check if networking module can load image
|
||||
if (RCT_DEBUG && ![_bridge.networking canHandleRequest:request]) {
|
||||
RCTLogError(@"No suitable image URL loader found for %@", imageTag);
|
||||
return ^{};
|
||||
}
|
||||
|
||||
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 =
|
||||
^(NSURLResponse *response, NSData *data, NSError *error) {
|
||||
|
||||
// Check for system errors
|
||||
if (error) {
|
||||
completionHandler(error, nil);
|
||||
return;
|
||||
} else if (!data) {
|
||||
completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for http errors
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode;
|
||||
if (statusCode != 200) {
|
||||
completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain
|
||||
code:statusCode
|
||||
userInfo:nil], nil);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Decode image
|
||||
decodeCancel = [weakSelf decodeImageData:data
|
||||
size:size
|
||||
scale:scale
|
||||
resizeMode:resizeMode
|
||||
completionBlock:completionHandler];
|
||||
};
|
||||
|
||||
// Check for cached response before reloading
|
||||
// TODO: move URL cache out of RCTImageLoader into its own module
|
||||
NSCachedURLResponse *cachedResponse = [_cache cachedResponseForRequest:request];
|
||||
if (cachedResponse) {
|
||||
processResponse(cachedResponse.response, cachedResponse.data, nil);
|
||||
return ^{};
|
||||
}
|
||||
|
||||
// Add missing png extension
|
||||
if (request.URL.fileURL && request.URL.pathExtension.length == 0) {
|
||||
NSMutableURLRequest *mutableRequest = [request mutableCopy];
|
||||
mutableRequest.URL = [NSURL fileURLWithPath:[request.URL.path stringByAppendingPathExtension:@"png"]];
|
||||
request = mutableRequest;
|
||||
}
|
||||
|
||||
// Download image
|
||||
RCTNetworkTask *task = [_bridge.networking networkTaskWithRequest:request completionBlock:
|
||||
^(NSURLResponse *response, NSData *data, NSError *error) {
|
||||
if (error) {
|
||||
completionHandler(error, nil);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the response
|
||||
// TODO: move URL cache out of RCTImageLoader into its own module
|
||||
RCTImageLoader *strongSelf = weakSelf;
|
||||
BOOL isHTTPRequest = [request.URL.scheme hasPrefix:@"http"];
|
||||
[strongSelf->_cache storeCachedResponse:
|
||||
[[NSCachedURLResponse alloc] initWithResponse:response
|
||||
data:data
|
||||
userInfo:nil
|
||||
storagePolicy:isHTTPRequest ? NSURLCacheStorageAllowed: NSURLCacheStorageAllowedInMemoryOnly]
|
||||
forRequest:request];
|
||||
|
||||
// Process image data
|
||||
processResponse(response, data, nil);
|
||||
|
||||
}];
|
||||
task.downloadProgressBlock = progressHandler;
|
||||
[task start];
|
||||
|
||||
return ^{
|
||||
[task cancel];
|
||||
if (decodeCancel) {
|
||||
decodeCancel();
|
||||
}
|
||||
OSAtomicOr32Barrier(1, &cancelled);
|
||||
};
|
||||
}
|
||||
|
||||
- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data
|
||||
@@ -314,6 +322,11 @@ RCT_EXPORT_MODULE()
|
||||
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) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user