Перейти к содержанию

Отложенная загрузка и подхват

Многие модули магазинов загружают виджет только при первом нажатии кнопки «Примерить». Это экономит запрос на каждой странице, но ломает одно: примерка, отправленная на одной странице, должна быть подхвачена на следующей, а виджет способен на это, только если он загружен. На этой странице объяснены проблема и небольшой лоадер, который её решает.

Опции и события самого виджета описаны в справочнике по виджету.

Зачем это нужно

Отправленная примерка оплачена, и виджет продолжает следить за ней, когда покупатель закрывает окно или переходит на другую страницу той же вкладки (см. «Примерка переживает своё окно» в справочнике по виджету). Запись о ней виджет хранит в sessionStorage вкладки. Следующая страница находит эту запись, когда выполняется TryOn.init().

Если ваш модуль загружает виджет только по первому клику, то на следующей странице init() не выполнит никто, и:

  • покупатель, перешедший на другой товар, не увидит никаких признаков того, что его примерка завершилась;
  • результат остаётся невостребованным, пока покупатель случайно не нажмёт кнопку снова.

Решение — загружать виджет сразу на любой странице, где вкладка хранит запись для вашего ключа, а во всех остальных случаях по-прежнему загружать его лениво. Для этого нужно знать, есть ли такая запись, не загружая виджет. Именно для этого существует лоадер.

Лоадер

<script src="https://api.ziex-tryon.com/embed/tryon-loader.js"></script>

Лоадер занимает несколько килобайт (ES5, без зависимостей) и отдаётся рядом с виджетом с теми же заголовками кэширования. Он добавляет один глобальный объект, ZiexTryOn, с двумя функциями и свойством version (версия самого лоадера; версия виджета — TryOn.version).

ZiexTryOn.hasPending(pk)

ZiexTryOn.hasPending('pk_YOUR_PUBLISHABLE_KEY'); // true | false

Возвращает true, когда в текущей вкладке есть запись о примерке, отправленной с этим публикуемым ключом: примерка ещё идёт либо завершилась, а её исход пока не показан. В остальных случаях, включая недоступный sessionStorage, возвращает false. Функция только читает хранилище: она не делает запросов и ничего не загружает.

ZiexTryOn.load([scriptUrl])

ZiexTryOn.load().then(function (TryOn) {
  TryOn.init({ apiKey: 'pk_YOUR_PUBLISHABLE_KEY' });
});

Один раз загружает скрипт виджета и возвращает промис, который разрешается значением window.TryOn. Повторные вызовы используют ту же загрузку и разрешаются тем же объектом, с каким бы аргументом их ни вызвали. Без аргумента загружается tryon-embed.js из каталога самого лоадера — то есть https://api.ziex-tryon.com/embed/tryon-embed.js, если лоадер подключён, как показано выше (и тогда, когда оптимизатор встроил или переименовал лоадер); передавайте scriptUrl, только если отдаёте виджет с другого адреса. Не подключайте tryon-embed.js ещё и сами.

Если скрипт не удалось загрузить (ошибка HTTP, сбой сети, скрипт без TryOn) или он не пришёл за 30 секунд, промис отклоняется, поэтому добавьте .catch(), если хотите отреагировать. Следующий вызов пробует снова; после таймаута он ждёт тот же тег <script>, так что виджет никогда не запускается дважды. Виджету нужен Promise; в браузере без него load() бросает исключение.

load() не вызывает init(). Это остаётся за вашей страницей, поэтому конфигурацию определяете вы.

Схема подключения

Подключайте лоадер на каждой странице, где может быть кнопка. На каждой странице спрашивайте hasPending() и, если ответ true, загружайте виджет сразу, иначе — по первому клику.

<button type="button" id="my-tryon-button" class="my-tryon-button">Примерить</button>

<script src="https://api.ziex-tryon.com/embed/tryon-loader.js"></script>
<script>
  (function () {
    var KEY = 'pk_YOUR_PUBLISHABLE_KEY';
    var config = {
      apiKey: KEY,
      launcher: false,                     // окно открывает ваша кнопка
      lockCategory: true,
      category: 'tops',
      productImage: 'https://shop.example/img/blue-shirt.jpg',
      productTitle: 'Синяя рубашка',
      productUrl: 'https://shop.example/blue-shirt',
      integration: 'my-shop-module/1.0.0'
    };

    var ready = null;
    function widget() {
      if (!ready) {
        ready = ZiexTryOn.load().then(function (TryOn) {
          TryOn.init(config);              // init() заодно подхватывает отправленную примерку
          return TryOn;
        });
      }
      return ready;
    }

    // Примерка, отправленная на более ранней странице этой вкладки: грузим сразу, чтобы её подхватить.
    if (ZiexTryOn.hasPending(KEY)) widget();

    // Во всех остальных случаях: грузим по первому клику.
    document.getElementById('my-tryon-button').addEventListener('click', function () {
      widget().then(function (TryOn) { TryOn.open(); });
    });
  })();
</script>

На что обратить внимание:

  • На каждой странице вызывайте init() с одним и тем же публикуемым ключом. Запись принадлежит ключу; страница с другим ключом её не увидит.
  • Вызывайте init() на каждой странице, где hasPending() возвращает true, даже если страница не показывает товар. Подхват выполняет init().
  • init() не открывает окно. Его открывает покупатель или ваша страница, и исход показывается в этот момент.
  • Одностраничный сайт, переключающий товары, должен вызывать TryOn.update(), а не destroy() и init(); см. update() или destroy().

Как сообщить покупателю, что результат ждёт

Пока исход ждёт следующего открытия окна, виджет делает две вещи, которыми может воспользоваться ваша кнопка.

1. Флаг на <html>. Атрибут data-tryon-ready принимает значение result или error. Он остаётся выставленным на каждой следующей странице вкладки, пока покупатель не откроет окно и не увидит исход. При launcher: false виджет не рисует кнопку, поэтому оформите свою:

.my-tryon-button { position: relative; }

html[data-tryon-ready] .my-tryon-button::after {
  content: "";
  position: absolute;
  top: -3px;
  right: -3px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #16a34a;               /* результат готов */
}
html[data-tryon-ready="error"] .my-tryon-button::after {
  background: #dc2626;               /* примерка не удалась */
}

Поскольку флаг — обычный CSS на корневом элементе, значок появляется ещё до того, как на странице выполнится любой ваш скрипт.

2. Событие ready. Оно отправляется один раз, на странице, где пришёл исход, после собственных событий исхода upload_completed, result или error:

TryOn.on('ready', function (e) {
  // e = { job_id: '…', kind: 'result' | 'error', background: true }
  console.log('Исход примерки ждёт:', e.kind);
});

Следующие страницы его не отправляют, а только выставляют флаг. Используйте флаг для состояния между страницами, а событие — для разовых реакций, например для аналитики.

Что хранится и как долго

  • Запись лежит в sessionStorage вкладки. Другие вкладки её не видят, а при закрытии вкладки она исчезает. Закрытая вкладка означает, что результат виден только в клиентском портале и истории заданий, но не на вашем сайте.
  • В записи — ключ идемпотентности отправленной примерки, номер задания (когда он известен), время отправки, оценка времени, категория и товар (название, ссылка, адрес картинки). Фото покупателя и вашего ключа API в ней нет.
  • Запись удаляется, когда исход показан, когда виджет убедился, что ничего не создано, по истечении attemptMaxMs (по умолчанию 45 минут) или при вызове TryOn.destroy().

Используйте лоадер, а не копируйте правило

Имя записи вычисляется из ключа по правилу внутри виджета. Не воспроизводите это правило в своём модуле, чтобы самостоятельно искать запись. Вызывайте ZiexTryOn.hasPending(). Лоадер и виджет выпускаются вместе, поэтому ответ всегда совпадает с тем, что найдёт сам виджет.

Что заморожено в версии 1

Эти части контракта не меняются в пределах версии 1, поэтому модуль, который на них опирается, продолжает работать:

  • слот хранилища в sessionStorage: имя ziex-tryon:attempt: и следом хеш FNV-1a (32 бита) от публикуемого ключа, записанный 8 шестнадцатеричными цифрами в нижнем регистре;
  • версия записи, v: 1;
  • флаг html[data-tryon-ready] со значениями result и error;
  • событие ready и его данные { job_id, kind, background };
  • интерфейс лоадера: ZiexTryOn.hasPending(pk) и ZiexTryOn.load([scriptUrl]).

Изменение любого из них делается только как новая версия записи, которую читают и старый, и новый код, и объявляется не позднее чем за 90 дней. Версия самого виджета — TryOn.version, строка semver, а его опции и события в пределах мажорной версии только добавляются.