Экономим трафик в SPA

Основная задача одностраничных приложений (SPA) – это коммуникация с сервером, а зачастую и с многочисленными серверами по средствам XHR. Но большинство данных достаточно загрузить один раз. Как это сделать красиво? Способов много. Однако, мы рассмотрим только один, с помощью обещаний Promises.

Существует некая модель Road, которая предоставляет данные:

export class Road {

   points = [
      [49.45, 34.23],
      [49.46, 34.22],
      [49.47, 34.21],
   ];

   getPoints() {
      return new Promise((resolve) => {
         resolve(this.points);
      });
   }
}

export default new Road();

Для упрощения понимания подхода, мы опустим код для загрузки точек с сервера. Достаточно отметить, что метод getPoints() возвращает объект new Promise().

Теперь, в разных частях приложения мы дергаем данную модель так:

const points = Road.getPoints();

Предельно просто и логично. Теперь, погрузимся в мир архитектуры SPA. Представим, что данный метод одновременно вызывается в трех разных контроллерах разных директив. Получается, что одни и те же данные, будут загружены несколько раз. Но если вспомнить, и почитать документацию по JavaScript, мы выясним, что объект Promise меняет своё состояние только один раз. Поэтому, единожды установившееся обещание, будет всегда выполненным (resolved) или отклоненным (rejected).

Решение такое, мы запоминаем обещание, и выдаем его всем потребителям. Тем самым устраняя сразу несколько серьезных проблем: 1. Гонка ресурсов. 2. Многократная загрузка одних и тех же данных. 3. Предварительная загрузка невостребованных данных.

 export class Road {

   promiseGetPoints = null;

   points = [
      [49.45, 34.23],
      [49.46, 34.22],
      [49.47, 34.21],
   ];

   getPoints() {
      if (!this.promiseGetPoints) {
         this.promiseGetPoints = new Promise((resolve) => {
            resolve(this.points);
         });
      }
      return this.promiseGetPoints;
   }
}

export default new Road();


Ну, или более красивый вариант:

export class Road {

   points = [
      [49.45, 34.23],
      [49.46, 34.22],
      [49.47, 34.21],
   ];

   @memoize
   getPoints() {
      new Promise((resolve) => {
         resolve(this.points);
      });
   }
}

export default new Road();

Декоратор @memoize делает очевидное, он кеширует возвращаемое значение getPoints().
Метод простой, однако, его мало кто использует, отдавая предпочтение многократной загрузке ненужных данных.

Спасибо.
Метки:
javscript, spa, promises