В версии 2.1.3, помимо прочего, был введён новый функционал для улучшения производительности сайтов, использующих hmpl.js.
Мемоизация запроса - это один из отличнейших способов оптимизации в программировании. «Что это и как оно работает?» - на эти вопросы я постараюсь ответить в данной статье.
Кстати, все нововведения, связанные с языком шаблонов, вы можете найти в тематическом тг-канале.
Понятие мемоизации
Прежде чем перейти к рассмотрению конкретного функционала, для начала рассмотрим данное понятия в программировании вообще.
Мемоизация - сохранение результатов выполнения функций для предотвращения повторных вычислений. Это один из способов оптимизации, применяемый для увеличения скорости выполнения компьютерных программ.
Перед вызовом функции проверяется, вызывалась ли функция ранее:
- если не вызывалась, то функция вызывается, и результат её выполнения сохраняется; 
- если вызывалась, то используется сохранённый результат. 
Примером мемоизации в JavaScript может быть следующий код:
// До внедрения мемоизации
const reverseText = (string) =>{
  const len = string.length;
  let reversedText = new Array();
  let j = 0;
  for (let i = len - 1; i >= 0; i--){
    reversedText[j] = string[i];
    j++;
  }
  return reversedText.join('');
}
const a = reverseText("a123"); // Срабатывает цикл
const b = reverseText("a123"); // Срабатывает цикл
// После внедрения мемоизации
const memoizeFn = (fn) => {
  const cache = {};
  return (string) => {
    if (string in cache) return cache[string];
    return (cache[string] = fn(string));
  };
};
const memoizedReverseText = memoizeFn(reverseText);
const a = memoizedReverseText("a123"); // Срабатывает цикл
const b = memoizedReverseText("a123"); // Не срабатывает циклМы создаём обёртку (функция высшего порядка) над уже существующий функцией, которая добавляет некое состояние, обозначенное cache. В кэше хранятся аргументы и, соответственно, значения, получаемые из функции. По ключу, если он равен входному аргументу, в объекте уже можно получить готовый результат, не переворачивая заново строку.
Это и есть та основа на которой строится вся оптимизация. Банально, мы не повторяем код заново, а лишь берём уже вычисленное значение.
Также, объект был назван кэшем неспроста. Кэш— это промежуточный буфер с быстрым доступом к нему, содержащий информацию, которая может быть запрошена с наибольшей вероятностью.
Тут уже можно вспомнить и память, которая располагается между процессором и оперативкой, но это уже явно немного другая история.
В целом, мемоизация повсеместно применяется в ПО, что делает её отличным способом по быстрому ускорить то или иное выполнение кода. Но у данного способа есть конечно и минусы.
Основным минусом, конечно, является лишнее выделение памяти на хранение результатов. Если функция выполняется один раз, то смысла мемоизировать её возвращаемые значения попросту нет.
Мемоизация в HMPL
Так как HMPL - это язык шаблонов для отображения пользовательского интерфейса с сервера на клиенте, то мемоизировать нужно будет http запросы. Соответственно, предполагаемым результатом будет сохранение HTML разметки. Вот пример того, как работает HMPL:
const newDiv = compile(
  `<div>
      <button>Get the square root of 256</button>
      <div>{{ src: "/api/getTheSquareRootOf256", after: "click:button" }}</div>
  </div>`
)().response;По слушателю событий на кнопке очевидно, что запрос на сервер может отправляться сколь угодно раз, но вот квадратный корень из 256 как был 16, так и будет, поэтому запрос, теоретически, будет приходить один и тот же.
Так вот, проблема предыдущих версий в том, что постоянно ставился новый элемент на каждый запрос, даже если ответ от запроса одинаковый.
Специально для оптимизации вот этого процесса было введено дополнительное поле, которое имеет название memo.  
const newDiv = compile(
  `<div>
      <button>Get the square root of 256</button>
      <div>{{ src: "/api/getTheSquareRootOf256", memo:true, after: "click:button" }}</div>
  </div>`
)().response;Значением оно принимает true или false. Работает только для объектов запросов, которые теоретически неоднократно отправляются.
Для наглядного отображения процесса была создана небольшая диаграмма:

Тут тоже фигурирует понятие кэша, которое уже было использовано ранее. Также, если мы берём HTTP запросы, то рассматриваются дополнительные понятия fresh и stale response, ревалидация и т.д. Это всё идёт из теории HTTP кэша. Более подробно этот момент рассматривается в mdn документации тут. Можно провести аналогию, что мемоизация в HMPL по логике сравнима с no-cache значением режима кэширования. 
Пример работы hmpl без мемоизации и с ней в DOM:
Без мемоизации:

С мемоизацией:

В ходе теста активно нажималась кнопка получения пользовательского интерфейса с сервера.
В одном случае, мы постоянно заменяем div на новый, хотя ответ от сервера приходит один и тот же, в другом же, мы сохраняем этот же элемент, но только если ответы одинаковы.
Мемоизация для типов файлов с расширением .hmpl
Также, мемоизация будет доступна не только для одного объекта запроса, но и для всех объектов, полученных из функции compile с включённой опцией memo:
const templateFn = hmpl.compile(
  `{ 
     {
       "src":"/api/test" 
     } 
   }`,
  {
    memo: true,
  }
);
const elementObj1 = templateFn();
const elementObj2 = templateFn();Она никак не помешает другим объектам запроса, которые срабатывают только один раз.
Так как на функции compile основана работа hmpl-loader, то в скором времени будет добавлена опция, при которой можно будет включить мемоизацию для всех файлов с расширением .hmpl:
module.exports = {
  module: {
    rules: [
      {
        test: /\.hmpl$/i,
        use: [{ loader: "hmpl-loader", options: { memo: true } }],
      },
    ],
  },
};Для этого уже открыт issue.
Всем большое спасибо за прочтение данной статьи!
P. S. Больше изменений, которые были внесены в новую версию 2.1.3, можно найти тут.
 
          