Все, что вам нужно знать о сервисных работниках

[Эта статья и все обновления изначально публикуются на allfront.io]

Мы все были там - вы заполняете форму, нажимаете "Отправить" и, к сожалению, что-то пошло не так с вашим подключением. Теперь вам нужно обновить страницу и снова все заполнить, потому что приложение сломалось 😤

Реальность такова, что прерывистые соединения распространены во всем мире - по состоянию на 2017 год 43 миллиона британцев сообщили о ненадежных медных соединениях. В Германии решение придерживаться медных оптоволоконных соединений в 1980-х годах сделало интернет-инфраструктуру одной из самых ненадежных в ЕС (по крайней мере, до тех пор, пока оптоволокно не будет реализовано в 2025 году).

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

TL; DR: Если вы не хотите объяснений, вы можете просмотреть ссылку на github напрямую. Пояснения сгруппированы по отраслям.

Что дальше?

Чтобы перевести ваши приложения в автономный режим, вам сначала нужно добавить сервисного работника. По своей сути сервис-воркер - это файл Javascript, который перехватывает и кэширует запросы. Самое классное в этом то, что он работает отдельно от основного потока, поэтому он может связываться с сервером, пока приложение не запущено. Вы можете использовать это, например, для добавления push-уведомлений в свое приложение.

Где подвох?

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

  • Нет доступа к локальному хранилищу - официальные документы Google утверждают, что это из-за его асинхронного дизайна. Вместо этого вы можете использовать что-то вроде indexedDB.
  • Сервисные работники работают только по HTTPS. Мы упоминаем об этом только потому, что стандартная среда разработки Angular работает через HTTP.
  • Сервисные работники могут бездействовать и также могут перезапускаться, когда браузер сочтет нужным. Это означает, что вам необходимо сохранить свое состояние.
  • Нет доступа к модели DOM из-за разделения задач в дизайне

📰 Хорошие новости

Одним из многих преимуществ преобразования вашего приложения в PWA является то, что вы также автоматически добавляете сервис-воркера во время установки!

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

И еще хорошие новости! Реализация сервис-воркеров в Angular уже кэширует ваши запросы. У вас есть эти отличные функции прямо из коробки:

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

🌶 Формы сложные

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

У вас нет времени терять зря, так что давайте начнем со всех скучных мелочей. Связанная демонстрация включает простой бэкэнд-сервер json (json-server) со списком задач pwa.

Обратите внимание, что из-за ограничений на развертывание stackblitz эту демонстрацию необходимо запускать локально. Это связано с множеством причин - обычный «ng-serve» не работает с сервис-воркерами, а серверная часть должна быть доступна на отдельном порту. Чтобы просмотреть сервис-воркер, вам нужно запустить предоставленную команду «start: service-worker».

Также следует отметить, что горячая перезагрузка не работает при использовании команды «start: service-worker».

Если у вас есть какие-либо вопросы или проблемы с любым из шагов, обратитесь к разделу вопросов и ответов внизу статьи.

Если все работает, как ожидалось, вы должны увидеть сервисного работника в инструментах разработки, и ваше приложение должно иметь приглашение на установку (маленький значок плюса справа от строки URL в случае хрома)

Что дальше?

Первый шаг - определить, находится ли пользователь в сети или офлайн. Объект window имеет несколько изящных событий, которые мы можем быстро прикрепить к теме rxjs, о которой вы можете прочитать больше здесь.

Следующим шагом является инициализация indexDB. Важно НЕ хранить данные в переменных, так как ваше приложение может перезапуститься в любой момент.

Есть несколько оболочек, которые мы можем использовать для оборачивания собственной indexDB браузера в Angular; В этом примере мы будем использовать ngx-indexed-db.

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

  • Отключите кнопки удаления и редактирования, когда пользователь не в сети - это означает, что мне не нужно отслеживать записи для удаления или обновления при синхронизации.
  • Одна служба используется для обработки связи API и автономной обработки - благодаря сохранению логики ее легче понять (но не так, как обслуживаемую).

Вы можете увидеть, как выглядит окончательный код, проверив наш git repo.

Ключевые выводы

Заставить ваше приложение работать в автономном режиме - дорого. Добавление офлайн-функциональности потребовало почти в 3 раза больше кода в сервисе (без учета тестов).

Вот краткое описание того, что необходимо сделать:

  • Используйте базу данных во внешнем интерфейсе и синхронизируйте свои удаленные данные
  • Обработка миграции данных для новых обновлений в базе данных вашего браузера без потери старых данных синхронизации
  • Поддерживайте обратную совместимость своих серверных API-интерфейсов для возможной синхронизации в более старых версиях приложений.
  • Обработка конфликтов: что произойдет, если два автономных пользователя редактируют одну и ту же запись? Есть два основных подхода: либо полностью избежать этой ситуации, убедившись, что общие данные нельзя изменить в автономном режиме, либо объединить записи.
  • Обработка версий приложения Angular - хотя вы можете разрешить angular обновлять ваше приложение «естественным образом» в фоновом режиме, вы можете просто подтолкнуть пользователей к последней версии напрямую.
  • Обработка ошибок неполной синхронизации
  • Переработка всех ваших сервисов для переключения между 2 источниками истины
  • Интеграция работает лучше, если вы используете angular-redux или ngrx.

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

Вам также потребуется значительная переработка серверной части и возможная оптимизация API для обработки очень больших запросов на синхронизацию.

Вопросы и ответы

Что делает команда «start: service-worker»?

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

Шучу - Команда по совместительству:

  • создает производственную версию проекта в папке dist
  • Развертывает встроенный код на порт 8080 с помощью http-сервера - поскольку мы не можем использовать ng-serve, нам нужен новый способ просмотра развернутых файлов.
  • Запускает простой бэкэнд json - бэкэнд должен быть отделен от приложения, чтобы эта демонстрация была реалистичной.

Мои изменения не отображаются, ПОМОГИТЕ!

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

Если использование последней версии приложения абсолютно необходимо, вы можете прослушать события сервис-воркера и вручную вызвать window.reload ().

Какие-нибудь другие советы по развитию?

  1. Вы должны иметь в виду, что при использовании инструментов разработчика сервис-воркер продолжает работать в фоновом режиме и никогда не перезагружается.
  2. Если вы хотите полностью удалить сервис-воркер, удалите файл ngsw.json. Когда сервисный работник Angular не может найти этот файл, он деактивируется как отказоустойчивый.
  3. При переключении версий приложения на веб-интерфейсе вы можете захотеть перенести свои данные. Вы можете узнать больше об обработке миграции в официальном руководстве по быстрому запуску ngx-indexed-db
  4. Рекомендуется сохранить систему управления версиями в вашем API - таким образом вы можете отделить старые API от новых и упростить отказ от старых API.
  5. Подумайте о добавлении какой-либо формы ведения журнала в свое приложение, чтобы отслеживать версии приложения в реальных условиях. Это упростит принятие решений об устаревании API в будущем.

Действительно ли страницы кешируются? Как я могу это подтвердить?

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

Если вы нажмете «Обновить», вы также увидите, что ваше приложение должно загружаться намного быстрее, но приложение todo само по себе мало, поэтому вы можете исправить это, уменьшив скорость соединения вручную с помощью инструментов chrome dev:

Произошло еще кое-что! Что мне теперь делать?

Оставьте комментарий со своей проблемой, и мы постараемся ответить вам в ближайшее время. Если вы хотите исправить это самостоятельно, документация Angular по сервис-воркерам - хорошее место для начала.