Асинхронная загрузка изображений

Идея в том, чтобы загружать изображения вне 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

Похожие записи

RxJs Subjects

Выдержки из доклада Андрея Алексеева (Tinkoff) про RxJs (Subject, Behaviour Subject, Replay Subject, Async Subject). Применение в Angular.

Добавить css link и js script динамически

const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css';
link.integrity = 'sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO'; // необязательно
link.crossOrigin = 'anonymous'; // необязательно
document.head.appendChild(link);

const script = document.createElement('script');
script.src = 'https://code.jquery.com/jquery-3.3.1.slim.min.js';
script.integrity = 'sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo'; // необязательно
s...