utils/ImagesCacheManager.tstypescript
import { QueueArray } from "../QueueArray";
export type HTMLImageElementExt = HTMLImageElement & {
__nodeIndex?: number;
atlasWidth?: number;
atlasHeight?: number;
};
export type ImagesCacheManagerCallback = (image: HTMLImageElementExt) => void;
interface IImagesCacheRequest {
src: string;
success: ImagesCacheManagerCallback;
}
class ImagesCacheManager {
public imagesCache: Record<string, HTMLImageElementExt>;
protected _counter: number;
protected _pendingsQueue: QueueArray<IImagesCacheRequest>;
protected _imageIndexCounter: number;
constructor() {
this.imagesCache = {};
this._counter = 0;
this._pendingsQueue = new QueueArray<IImagesCacheRequest>();
this._imageIndexCounter = 0;
}
public load(src: string, success: ImagesCacheManagerCallback) {
if (this.imagesCache[src]) {
success(this.imagesCache[src]);
} else {
let req = { src: src, success: success };
if (this._counter >= 1) {
this._pendingsQueue.unshift(req);
} else {
this._exec(req);
}
}
}
protected _exec(req: IImagesCacheRequest) {
this._counter++;
const that = this;
let img: HTMLImageElementExt = new Image();
img.crossOrigin = "";
img.onload = function () {
that.imagesCache[req.src] = img;
img.__nodeIndex = that._imageIndexCounter++;
req.success(img);
that._dequeueRequest();
};
img.onerror = function () {
that._dequeueRequest();
};
img.src = req.src;
}
protected _dequeueRequest() {
this._counter--;
if (this._pendingsQueue.length && this._counter < 1) {
while (this._pendingsQueue.length) {
let req = this._pendingsQueue.pop();
if (req) {
if (this.imagesCache[req.src]) {
if (this._counter <= 0) {
this._counter = 0;
} else {
this._counter--;
}
req.success(this.imagesCache[req.src]);
} else {
this._exec(req);
break;
}
}
}
}
}
}
export { ImagesCacheManager };