Образ мышления работника сферы услуг

Как думать, думая о работниках сферы услуг.

Дэйв Геддес
Дэйв Геддес

Сервисные работники сильны, и им абсолютно стоит учиться. Они позволяют вам предоставить пользователям совершенно новый уровень опыта. Ваш сайт может загружаться мгновенно . Он может работать в автономном режиме . Его можно установить как приложение для конкретной платформы, и оно будет выглядеть таким же совершенным, но с доступностью и свободой Интернета.

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

Мы с разработчиками Google недавно работали над проектом Service Workies — бесплатной игрой для понимания сервисных работников. Создавая его и работая со сложными тонкостями сервисных работников, я столкнулся с несколькими препятствиями. Больше всего мне помогло придумать несколько изобразительных метафор. В этой статье мы исследуем эти ментальные модели и поразмышляем над парадоксальными особенностями, которые делают сервисных работников одновременно сложными и удивительными.

То же самое, но другое

При написании сервисного работника многие вещи кажутся вам знакомыми. Вы сможете использовать свои любимые новые возможности языка JavaScript. Вы слушаете события жизненного цикла так же, как и события пользовательского интерфейса. Вы управляете потоком управления с помощью обещаний, как вы привыкли.

Но поведение других сервисных работников заставляет вас в замешательстве чесать затылок. Особенно, когда вы обновляете страницу и не видите примененных изменений кода.

Новый слой

Обычно при создании сайта вам нужно подумать только о двух уровнях: клиенте и сервере. Сервисный работник — это совершенно новый уровень, расположенный посередине.

Сервис-воркер выступает в качестве промежуточного уровня между клиентом и сервером.

Думайте о своем сервис-воркере как о своего рода расширении браузера , которое ваш сайт может установить в браузер вашего пользователя. После установки сервис-воркер расширяет браузер вашего сайта мощным средним уровнем. Этот уровень сервисного работника может перехватывать и обрабатывать все запросы, которые делает ваш сайт.

Уровень сервисного работника имеет свой собственный жизненный цикл , независимый от вкладки браузера. Простого обновления страницы недостаточно для обновления сервис-воркера — точно так же, как вы не ожидаете, что обновление страницы приведет к обновлению кода, развернутого на сервере. Каждый слой имеет свои уникальные правила обновления.

В игре Service Workies мы раскрываем множество деталей жизненного цикла сервис-воркера и даем вам массу практики по работе с ним.

Мощный, но ограниченный

Наличие сервисного работника на вашем сайте дает вам невероятные преимущества. Ваш сайт может:

  • работают безупречно, даже когда пользователь оффлайн
  • получить значительный прирост производительности за счет кэширования
  • используйте push-уведомления
  • быть установлен как PWA

Все, что могут сделать работники сферы обслуживания, ограничено замыслом. Они не могут делать ничего синхронно или в том же потоке, что и ваш сайт. Это означает отсутствие доступа к:

  • локальное хранилище
  • ДОМ
  • окно

Хорошей новостью является то, что ваша страница может взаимодействовать со своим сервис-воркером несколькими способами, включая прямой postMessage , каналы сообщений «один-к-одному» и широковещательные каналы «один-ко-многим».

Долговечный, но недолговечный

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

В Service Workies мы визуализируем эту концепцию с помощью Kolohe (дружественного сервисного работника), перехватывающего и обрабатывающего запросы.

Остановлено

Несмотря на то, что сервисные работники кажутся бессмертными, их можно остановить практически в любой момент. Браузер не хочет тратить ресурсы на сервис-воркера, который в данный момент ничего не делает. Остановка — это не то же самое, что прекращение работы : сервис-воркер остается установленным и активированным. Его просто усыпили. В следующий раз, когда это понадобится (например, для обработки запроса), браузер снова активирует его.

Подожди до

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

Этот пример сообщает браузеру, что наш сервис-воркер не завершит установку до тех пор, пока кэш assets не будет создан и заполнен изображением меча:

self.addEventListener("install", event => {
  event.waitUntil(
    caches.open("assets").then(cache => {
      return cache.addAll(["/weapons/sword/blade.png"]);
    })
  );
});

Следите за глобальным состоянием

Когда происходит этот запуск/остановка, глобальная область действия сервисного работника сбрасывается. Поэтому будьте осторожны и не используйте какое-либо глобальное состояние в своем сервис-воркере, иначе вам будет грустно, когда в следующий раз он снова проснется и будет иметь состояние, отличное от ожидаемого.

Рассмотрим этот пример, в котором используется глобальное состояние:

const favoriteNumber = Math.random();
let hasHandledARequest = false;

self.addEventListener("fetch", event => {
  console.log(favoriteNumber);
  console.log(hasHandledARequest);
  hasHandledARequest = true;
});

При каждом запросе этот сервис-воркер записывает номер, скажем, 0.13981866382421893 . Переменная hasHandledARequest также изменится на true . Теперь сервис-воркер некоторое время простаивает, поэтому браузер останавливает его. В следующий раз, когда поступит запрос, сервис-воркер снова понадобится, поэтому браузер его разбудит. Его сценарий оценивается еще раз . Теперь hasHandledARequest сбрасывается в false , а favoriteNumber имеет совершенно другое значение — 0.5907281835659033 .

Вы не можете полагаться на сохраненное состояние в сервис-воркере. Кроме того, создание экземпляров таких вещей, как каналы сообщений, может вызвать ошибки: вы будете получать новый экземпляр каждый раз, когда сервис-воркер останавливается/запускается.

В главе 3 Service Workies мы представляем, что наш остановленный сервис-воркер теряет весь цвет, пока ожидает пробуждения.

визуализация остановленного сервис-воркера

Вместе, но отдельно

Вашей страницей может управлять только один работник службы одновременно. Но на нем могут быть установлены сразу два сервис-воркера. Когда вы вносите изменения в код своего сервис-воркера и обновляете страницу, вы фактически вообще не редактируете своего сервис-воркера. Сервисные работники неизменны . Вместо этого вы делаете совершенно новый. Этот новый сервисный работник (назовем его SW2) будет установлен , но еще не активируется . Он должен дождаться завершения текущего сервисного работника (SW1) (когда ваш пользователь покинет ваш сайт).

Возиться с кэшами других сервис-воркеров

Во время установки SW2 может выполнить настройку — обычно создавая и заполняя кеши. Но будьте осторожны: этот новый сервис-воркер имеет доступ ко всему, к чему имеет доступ текущий сервис-воркер. Если вы не будете осторожны, ваш новый ожидающий сервис-воркер может серьезно испортить ситуацию вашему текущему сервис-воркеру. Несколько примеров, которые могут вызвать у вас затруднения:

  • SW2 может удалить кэш, который активно использует SW1.
  • SW2 может редактировать содержимое кэша, который использует SW1, в результате чего SW1 отвечает активами, которые страница не ожидает.

Пропустить пропуститьОжидание

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

Начать с чистого листа

Чтобы не допустить, чтобы ваши сервисные работники засоряли друг друга, нужно убедиться, что они используют разные кеши. Самый простой способ добиться этого — изменить имена используемых ими кэшей.

const version = 1;
const assetCacheName = `assets-${version}`;

self.addEventListener("install", event => {
  caches.open(assetCacheName).then(cache => {
    // confidently do stuff with your very own cache
  });
});

При развертывании нового сервис-воркера вы обновляете version , чтобы она делала то, что ей нужно, с полностью отдельным кешом от предыдущего сервис-воркера.

визуализация кэша

Конец чистый

Как только ваш сервис-воркер достигает activated состояния, вы знаете, что он вступил во владение, и предыдущий сервис-воркер становится избыточным. На этом этапе важно очистить старый сервис-воркер. Он не только учитывает ограничения хранилища кэша ваших пользователей, но также может предотвратить непреднамеренные ошибки.

Метод caches.match() — это часто используемый ярлык для извлечения элемента из любого кэша, где есть совпадение. Но он перебирает кеши в том порядке, в котором они были созданы. Предположим, у вас есть две версии файла сценария app.js в двух разных кэшах assets-1 и assets-2 . Ваша страница ожидает новый скрипт, хранящийся в assets-2 . Но если вы не удалили старый кеш, caches.match('app.js') вернет старый из assets-1 и, скорее всего, сломает ваш сайт.

Все, что нужно для очистки после предыдущих сервис-воркеров, — это удалить весь кеш, который не нужен новому сервис-воркеру:

const version = 2;
const assetCacheName = `assets-${version}`;

self.addEventListener("activate", event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cacheName => {
          if (cacheName !== assetCacheName){
            return caches.delete(cacheName);
          }
        });
      );
    });
  );
});

Чтобы не допустить, чтобы ваши сервисные работники били друг друга, требуется немного работы и дисциплины, но оно того стоит.

Образ мышления работника сферы услуг

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

Если вы хотите понять все это, сыграв в игру , то вам повезло! Сыграйте в Service Workies , где вы узнаете, как сервисный работник убивает автономных зверей.