[change] Image uses decode() not requestIdleCallback()

Chrome heavily throttles `requestIdleCallback` while scrolling, which
causes delays in image loading. Instead, use the relatively new
`decode()` API to decode the image off the main thread and prevent jank,
without delaying loading itself.

Fix #764
Ref #759
This commit is contained in:
Nicolas Gallagher
2018-06-03 11:32:54 -07:00
parent d5c6b98340
commit b8f54f61f0
2 changed files with 14 additions and 19 deletions
+4 -18
View File
@@ -16,7 +16,6 @@ import ImageResizeMode from './ImageResizeMode';
import ImageSourcePropType from './ImageSourcePropType';
import ImageStylePropTypes from './ImageStylePropTypes';
import ImageUriCache from './ImageUriCache';
import requestIdleCallback, { cancelIdleCallback } from '../../modules/requestIdleCallback';
import StyleSheet from '../StyleSheet';
import StyleSheetPropType from '../../modules/StyleSheetPropType';
import View from '../View';
@@ -78,9 +77,6 @@ type State = {
shouldDisplaySource: boolean
};
const getAssetTimeout = source =>
typeof source === 'object' && source.timeout ? source.timeout : 1000;
class Image extends Component<*, State> {
static displayName = 'Image';
@@ -126,7 +122,6 @@ class Image extends Component<*, State> {
_imageRequestId = null;
_imageState = null;
_isMounted = false;
_loadRequest = null;
constructor(props, context) {
super(props, context);
@@ -216,6 +211,7 @@ class Image extends Component<*, State> {
const hiddenImage = displayImage
? createElement('img', {
alt: accessibilityLabel || '',
decode: 'async',
draggable,
ref: this._setImageRef,
src: displayImage,
@@ -252,22 +248,12 @@ class Image extends Component<*, State> {
_createImageLoader() {
const { source } = this.props;
this._destroyImageLoader();
this._loadRequest = requestIdleCallback(
() => {
const uri = resolveAssetUri(source);
this._imageRequestId = ImageLoader.load(uri, this._onLoad, this._onError);
this._onLoadStart();
},
{ timeout: getAssetTimeout(source) }
);
const uri = resolveAssetUri(source);
this._imageRequestId = ImageLoader.load(uri, this._onLoad, this._onError);
this._onLoadStart();
}
_destroyImageLoader() {
if (this._loadRequest) {
cancelIdleCallback(this._loadRequest);
this._loadRequest = null;
}
if (this._imageRequestId) {
ImageLoader.abort(this._imageRequestId);
this._imageRequestId = null;
+10 -1
View File
@@ -50,7 +50,16 @@ const ImageLoader = {
id += 1;
const image = new window.Image();
image.onerror = onError;
image.onload = onLoad;
image.onload = e => {
// avoid blocking the main thread
if (typeof image.decode === 'function') {
image.decode().then(() => { onLoad(e) });
} else {
setTimeout(() => {
onLoad(e);
}, 0);
}
};
image.src = uri;
requests[`${id}`] = image;
return id;