Merge pull request #9558 from tschaub/unlisten

Stop listening for image decoding
This commit is contained in:
Tim Schaub
2019-05-16 11:46:15 -06:00
committed by GitHub
4 changed files with 92 additions and 32 deletions
+30 -22
View File
@@ -58,9 +58,9 @@ class ImageWrapper extends ImageBase {
/** /**
* @private * @private
* @type {Array<import("./events.js").EventsKey>} * @type {function():void}
*/ */
this.imageListenerKeys_ = null; this.unlisten_ = null;
/** /**
* @protected * @protected
@@ -121,7 +121,7 @@ class ImageWrapper extends ImageBase {
this.state = ImageState.LOADING; this.state = ImageState.LOADING;
this.changed(); this.changed();
this.imageLoadFunction_(this, this.src_); this.imageLoadFunction_(this, this.src_);
this.imageListenerKeys_ = listenImage( this.unlisten_ = listenImage(
this.image_, this.image_,
this.handleImageLoad_.bind(this), this.handleImageLoad_.bind(this),
this.handleImageError_.bind(this) this.handleImageError_.bind(this)
@@ -142,7 +142,10 @@ class ImageWrapper extends ImageBase {
* @private * @private
*/ */
unlistenImage_() { unlistenImage_() {
unlistenImage(this.imageListenerKeys_); if (this.unlisten_) {
this.unlisten_();
this.unlisten_ = null;
}
} }
} }
@@ -150,31 +153,36 @@ class ImageWrapper extends ImageBase {
* @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image element. * @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} image Image element.
* @param {function():any} loadHandler Load callback function. * @param {function():any} loadHandler Load callback function.
* @param {function():any} errorHandler Error callback function. * @param {function():any} errorHandler Error callback function.
* @return {Array<import("./events.js").EventsKey>} listener keys. * @return {function():void} Callback to stop listening.
*/ */
export function listenImage(image, loadHandler, errorHandler) { export function listenImage(image, loadHandler, errorHandler) {
const img = /** @type {HTMLImageElement} */ (image); const img = /** @type {HTMLImageElement} */ (image);
if (img.decode) { if (img.decode) {
img.decode().then(loadHandler).catch(errorHandler); const promise = img.decode();
return null; let listening = true;
} else { const unlisten = function() {
const listenerKeys = [ listening = false;
listenOnce(img, EventType.LOAD, loadHandler), };
listenOnce(img, EventType.ERROR, errorHandler) promise.then(function() {
]; if (listening) {
return listenerKeys; loadHandler();
}
}).catch(function(error) {
if (listening) {
errorHandler();
}
});
return unlisten;
} }
} const listenerKeys = [
listenOnce(img, EventType.LOAD, loadHandler),
/** listenOnce(img, EventType.ERROR, errorHandler)
* @param {Array<import("./events.js").EventsKey>} listenerKeys listener keys. ];
*/ return function unlisten() {
export function unlistenImage(listenerKeys) {
if (listenerKeys) {
listenerKeys.forEach(unlistenByKey); listenerKeys.forEach(unlistenByKey);
listenerKeys = null; };
}
} }
export default ImageWrapper; export default ImageWrapper;
+8 -5
View File
@@ -4,7 +4,7 @@
import Tile from './Tile.js'; import Tile from './Tile.js';
import TileState from './TileState.js'; import TileState from './TileState.js';
import {createCanvasContext2D} from './dom.js'; import {createCanvasContext2D} from './dom.js';
import {listenImage, unlistenImage} from './Image.js'; import {listenImage} from './Image.js';
class ImageTile extends Tile { class ImageTile extends Tile {
@@ -46,9 +46,9 @@ class ImageTile extends Tile {
/** /**
* @private * @private
* @type {Array<import("./events.js").EventsKey>} * @type {function():void}
*/ */
this.imageListenerKeys_ = null; this.unlisten_ = null;
/** /**
* @private * @private
@@ -134,7 +134,7 @@ class ImageTile extends Tile {
this.state = TileState.LOADING; this.state = TileState.LOADING;
this.changed(); this.changed();
this.tileLoadFunction_(this, this.src_); this.tileLoadFunction_(this, this.src_);
this.imageListenerKeys_ = listenImage( this.unlisten_ = listenImage(
this.image_, this.image_,
this.handleImageLoad_.bind(this), this.handleImageLoad_.bind(this),
this.handleImageError_.bind(this) this.handleImageError_.bind(this)
@@ -148,7 +148,10 @@ class ImageTile extends Tile {
* @private * @private
*/ */
unlistenImage_() { unlistenImage_() {
unlistenImage(this.imageListenerKeys_); if (this.unlisten_) {
this.unlisten_();
this.unlisten_ = null;
}
} }
} }
+8 -5
View File
@@ -7,7 +7,7 @@ import EventTarget from '../events/Target.js';
import EventType from '../events/EventType.js'; import EventType from '../events/EventType.js';
import ImageState from '../ImageState.js'; import ImageState from '../ImageState.js';
import {shared as iconImageCache} from './IconImageCache.js'; import {shared as iconImageCache} from './IconImageCache.js';
import {listenImage, unlistenImage} from '../Image.js'; import {listenImage} from '../Image.js';
class IconImage extends EventTarget { class IconImage extends EventTarget {
@@ -53,9 +53,9 @@ class IconImage extends EventTarget {
/** /**
* @private * @private
* @type {Array<import("../events.js").EventsKey>} * @type {function():void}
*/ */
this.imageListenerKeys_ = null; this.unlisten_ = null;
/** /**
* @private * @private
@@ -191,7 +191,7 @@ class IconImage extends EventTarget {
} catch (e) { } catch (e) {
this.handleImageError_(); this.handleImageError_();
} }
this.imageListenerKeys_ = listenImage( this.unlisten_ = listenImage(
this.image_, this.image_,
this.handleImageLoad_.bind(this), this.handleImageLoad_.bind(this),
this.handleImageError_.bind(this) this.handleImageError_.bind(this)
@@ -233,7 +233,10 @@ class IconImage extends EventTarget {
* @private * @private
*/ */
unlistenImage_() { unlistenImage_() {
unlistenImage(this.imageListenerKeys_); if (this.unlisten_) {
this.unlisten_();
this.unlisten_ = null;
}
} }
} }
+46
View File
@@ -0,0 +1,46 @@
import {listenImage} from '../../../src/ol/Image.js';
describe('HTML Image loading', function() {
let handleLoad, handleError, img;
beforeEach(function() {
handleLoad = sinon.spy();
handleError = sinon.spy();
img = new Image();
});
it('handles load event', function(done) {
img.src = 'spec/ol/data/dot.png';
listenImage(img, handleLoad, handleError);
setTimeout(function() {
expect(handleLoad).to.be.called();
expect(handleError).not.to.be.called();
done();
}, 200);
});
it('handles error event', function(done) {
img.src = 'invalid.jpeg';
listenImage(img, handleLoad, handleError);
setTimeout(function() {
expect(handleLoad).not.to.be.called();
expect(handleError).to.be.called();
done();
}, 200);
});
it('handles cancelation', function(done) {
img.src = 'spec/ol/data/dot.png';
listenImage(img, handleLoad, handleError)();
setTimeout(function() {
expect(handleLoad).not.to.be.called();
expect(handleError).not.to.be.called();
done();
}, 200);
});
});