Асинхронная загрузка изображений
Идея в том, чтобы загружать изображения вне DOM. По-умолчанию показывается прелоадер, а по окончанию загрузки подменяется ссылка на изображение. Так как изображение попадает в кэш браузера, то оно мгновенно появиться у пользователя.
/**
* Загрузить изображение асинхронно
* @param url - image URL
*/
private _asyncImage(url: string): Promise<HTMLImageElement> {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = () => reject(new Error(`Could not load image: ${url}`));
img.src = url;
});
}
/**
* Загрузить изображение
* @param url - image URL
*/
private loadImageAsync(url: string): Observable<HTMLImageElement> {
return new Observable(observer => {
const img = new Image();
img.onload = () => {
observer.next(img);
observer.complete();
};
img.onerror = () => observer.error(new Error(`Could not load image: ${url}`));
img.src = url;
});
}
/**
* Проверить успешность загрузки изображения.
* @param img - загружаемое изображения
*/
private _isImageLoaded(img: HTMLImageElement): boolean {
if (!img.complete) {
return false;
}
if (img.naturalWidth + img.naturalHeight === 0) {
return false;
}
return true;
}
Использование
this._asyncImage(value)
.then(img => {
this._isImageLoaded(img) ? this._setBackgroundImage(value) : this._setDefaultImage();
})
.catch(() => this._setDefaultImage());
В методах _setDefaultImage
и _setBackgroundImage
в зависимости от ситуации происходит подмена:
src
для<img>
url()
дляbackground-image