Skip to content

Commit

Permalink
[change] Image uses decode() not requestIdleCallback()
Browse files Browse the repository at this point in the history
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
  • Loading branch information
necolas committed Jun 3, 2018
1 parent d5c6b98 commit b8f54f6
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 19 deletions.
22 changes: 4 additions & 18 deletions packages/react-native-web/src/exports/Image/index.js
Expand Up @@ -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';
Expand Down Expand Up @@ -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';

Expand Down Expand Up @@ -126,7 +122,6 @@ class Image extends Component<*, State> {
_imageRequestId = null;
_imageState = null;
_isMounted = false;
_loadRequest = null;

constructor(props, context) {
super(props, context);
Expand Down Expand Up @@ -216,6 +211,7 @@ class Image extends Component<*, State> {
const hiddenImage = displayImage
? createElement('img', {
alt: accessibilityLabel || '',
decode: 'async',
draggable,
ref: this._setImageRef,
src: displayImage,
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 10 additions & 1 deletion packages/react-native-web/src/modules/ImageLoader/index.js
Expand Up @@ -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;
Expand Down

0 comments on commit b8f54f6

Please sign in to comment.