Service workers что это
Подводные камни Service Workers
В этом коротеньком очерке я опишу те вещи о service workers, о которых я бы хотел прочесть год или хотя бы полгода назад и тем самым избежать очень долгого и мучительного периода отладки приложения.
Если вы попали сюда по запросу типа «какого черта мой сервис воркер не работает на продакшене?», добро пожаловать под кат.
Для тех, кто вообще не в курсе о чем речь, то очень вкратце — service worker это скрипт, который выполняется браузером в фоне, отдельно от веб-страницы и способен выполнять функции для которых не требуется взаимодействие со страницей или пользователем.
Полную документацию найти не сложно, но вот ссылка.
Еще мне очень пригодился вот этот материал и мне очень жаль что я невнимательно с ним ознакомился когда только начал знакомство с ServiceWorker API.
На практике Service Worker API позволяет делать такую магическую вещь, как кеширование файлов онлайн веб-приложения на локальное устройство пользователя и затем работать полностью в оффлайне, если нужно.
В будущем планируется добавить такие классные вещи как синхронизация кеша в фоне, то есть даже если пользователь не находится сейчас на вашем сайте, сервис-воркер все равно сможет запуститься и скачать обновления например. А также доступ к PushApi из фона опять же (то есть при получении обновления отправить вам пуш-уведомление).
Чего я не знал до недавнего времени, так это того, что даже если пользователь сейчас на вашем сайте, это никак не гарантирует того, что service worker будет работать все время. И ни в коем случае нельзя полагаться на global scope воркера.
То есть вот такая схема работы привела меня к очень плачевным последствиям и длительному процессу отладки приложения (внимание, плохой код, НЕ использовать ни в коем случае):
регистрация/установка service worker
Index.html
Код воркера, с прослушкой fetch и подменой ответа
service-worker.js
И все бы ничего, если бы не факт, что по истечению случайного количества времени (3-10 минут) работы приложения, service worker начинал перенаправлять запросы “в никуда”, а точнее в что-то типа «file://undefined/images/image1.png»
То есть спустя какое-то время переменная self.filesDir попросту удаляется и мы получаем тонну 404 file not found вместо картинок.
Естественно ни один уважающий себя программист не будет тестировать приложение целых 5 минут. Поэтому баг обнаруживает в лучшем случае тестер. А обычно даже клиент. Потому что сами знаете, эти тестеры… И вообще, тестирование никто не оплачивал, скажите спасибо что при старте не крашится.
В общем чтобы долго не затягивать, проблема в том, что если service worker не используется [какое-то время], то браузер его прибивает (извините не придумал более уместного перевода для слова terminate) и затем при следующем обращении стартует снова. Соответственно, новая копия воркера знать не знает о чем там его мертвый предшественник общался с веб-страницей и у него нет никаких сведений о том, откуда брать файлы.
Поэтому, если Вам нужно что-то сохранить — делайте это в перманентном хранилище, а именно в IndexedDB.
Еще одна заметка — говорят воркер не может использовать синхронные API, поэтому localStorage API не удастся использовать. Но я лично не пробовал.
Кстати, отладка в моем случае затянулась еще и потому что даже когда я тестировал долго-долго (минут 7) в надежде воспроизвести все-таки баг, у меня не получалось, так как при открытом окне Developer Tools коварный chrome не убивает воркер. Хоть и сообщает об этом лаконичным сообщением в логах “Service Worker termination by a timeout was canceled because DevTools is attached”
Собственно тут до меня и дошло, почему мои многократные попытки выяснить почему ServiceWorker у меня работает иначе чем у клиента на production провалились…
В общем после того как я убрал установку пути в переменной и перенес это в indexedDB мои несчастья закончились и мне снова начал нравиться ServiceWorker API.
А вот собственно рабочий пример кода, который можно взять и использовать в отличие от предыдущего:
Некоторые тонкости использования Service Workers
Предисловие
Сервис-воркеры (Service Workers, да простят меня читатели) сегодня являются полезным дополнением к основной функциональности сайта: тут и работа в оффлайне, и фоновая синхронизация данных, и модные пуш-уведомления.
Однако большое количество статей про сервис-воркеры выглядят достаточно сжато и описывают простые примеры. Я попробую обратить внимание на некоторые особенности работы сервис-воркеров, так что требуются какие-то базовые знания. Отправной точкой может быть эта статья (перевод) или чуть более подробная статья.
Несколько сервис-воркеров на одном домене
У регистрации (registration) конкретного сервис-воркера есть такое понятие, как scope. Оно определяет, какие страницы на определённом домене будут подпадать под её контроль. При этом можно регистрировать несколько сервис-воркеров на одном домене, но с разными scope. Если попробовать зарегистрировать их с разными именами, но одним scope, то установленный позднее воркер будет «замещать» своего более раннего брата.
Кстати, для того, чтобы файл по указанному пути можно было установить в качестве сервис-воркера по пути выше (такое поведение запрещено по умолчанию, увеличивать путь можно, уменьшать — нет), то для этого можно использовать http-заголовок Service-Worker-Allowed.
Метод getRegistration() без параметров возвращает подходящую для текущей страницы регистрацию сервис-воркера, возможно, неактивную. Это также значит то, что по вложенному пути мы будем получать ту же самую регистрацию, если нет более подходящей. Это может приводить к неожиданностям, если ожидается работа нескольких сервис-воркеров на одном домене.
Рассмотрим пример: у нас есть установленный сервис-воркер со scope /. Пусть это будет новостной сайт и мы предоставляем оффлайновые версии текстов. Также есть панель управления по пути /admin/ со своим собственным сервис-воркером. Если второй сервис-воркер ещё не попытались установить, то getRegistaration() будет возвращать регистрацию первого сервис-воркера и это может приводить к ошибкам (например, мы будем слать нотификации из панели администратора в сервис-воркер, не готовый к ним вовсе).
getRegistration имеет опциональный параметр — scope. Если его указать, то метод вернёт регистрацию, наиболее подходящую (не обязательно равную) переданному scope. Тем самым мы можем отписываться от сервис-воркеров на вложенных страницах или получать вообще любые регистрации с текущего домена, нужно лишь знать подходящие scope.
А если мы не знаем все scope, то есть метод getRegistrations(), который просто возвращает все регистрации с текущего домена в виде массива. Требуется Firefox или Chrome 45+.
Связь между страницей и сервис-воркером
Возможность обмена данными между сервис-воркером и подчинённой страницей может привести довольно к оригинальным схемам работы. Например, можно сразу присылать данные из кеша, параллельно запрашивая новые; как только будут новые данные — положить их в кеш и прислать на страницу.
Пример на serviceworke.rs показывает простой способ общения с сервис-воркером:
Здесь controller — сервис-воркер, контролирующий страницу. В свежих браузерах (все версии Firefox и Chrome 51+) можно достаточно просто ответить на такой запрос:
В более старых версиях приходилось обходить все вкладки и находить нужную, а то и создавать руками MessageChannel. Также теперь у нас есть возможность отправлять сообщение вкладке из события fetch. Всё это описано в статье, разве что современное апи у нас уже есть.
Другой момент — хранение данных в сервис-воркере. Люди, уже опробовавшие сервис-воркеры, могли заметить, что LocalStorage там нет. Всё потому, что в сервис-воркерах был взят курс на полностью асинхронное апи (за исключением, пожалуй, importScripts). Но внутри всё ещё остаются доступны:
Или как-то так, но тогда нужно будет иметь в одном месте полный список возможных кешей.
Но при всём этом стоит помнить, что никто не гарантирует 100% сохранность данных в хранилищах. Браузер может автоматически чистить CacheStorage и indexedDB при нехватке места на диске, да и пользователь может сделать это сам.
Кроссдоменные запросы и прочее взаимодействие с другими доменами
С введением fetch ситуация могла показаться немного запутанной (там есть разные режимы запроса/ответа), а с сервис-воркерами всё становится в два раза сложнее: один fetch на стороне клиента, второй — на стороне сервис-воркера.
Самое простое понимание, к которому можно придти: «обмануть» CORS и получить доступ к контенту с другого домена без заголовков не получится. Важно разделять два вида использования: с доступом со стороны javascript и без него. Например, подменить одну картинку другой можно без проблем: достаточно указать в fetch сервис-воркера mode: ‘no-cors’ и не важно, какие там заголовки. Если не использовать ‘no-cors’, fetch будет ожидать CORS заголовки и в случае их отсутствия всё окончится ошибкой.
Если говорить более строго, то любой запрос (Request) со страницы имеет mode. Например, запрос картинки — ‘no-cors’, а запрос картинки с атрибутом crossOrigin (anonymous или use-credentials) — уже ‘cors’. Запросы через XMLHttpRequest всегда в режиме ‘cors’. А fetch позволяет задавать режим напрямую.
Ответ (Response) имеет свойство type. Запросы на текущий домен — ‘basic’. Иначе, если режим запроса — ‘cors’, то type ответа тоже будет ‘cors’, при наличии необходимых заголовков. Режим ответа ‘opaque’ можно получить на запрос в режиме ‘no-cors’, в нём нельзя получить доступ к каким-либо данным ответа.
Здесь описаны не все возможные виды режимов запросов, но этого должно быть достаточно для общего понимания. Больше информации можно почерпнуть из статьи с описанием fetch.
Теперь попробуем всё скомбинировать. Со страницы уходит запрос, его перехватывает сервис-воркер и делает свой fetch, получает ответ. До текущего момента ситуация разобрана, но теперь будет нюанс: при передаче ответа с типом ‘opaque’ в ответ на запрос страницы. который был сделан не с режимом ‘no-cors’, мы получим ошибку.
Помимо просто запросов, мы можем установить сервис-воркер на другой домен. Нет, мы не получим контроль за другой страницей через наш сервис-воркер — условия на сервис-воркер остаются теми же (сам скрипт должен быть на том же домене, на который регистрируется воркер). Для этого можно использовать iframe с нужного домена — разрешений от пользователя не требуется и iframe можно сделать просто невидимым.
Другая интересная возможность, которая сейчас находится в своей ранней версии — Foreign Fetch. Если обычный сервис-воркер контролирует запросы со страницы в своём scope (страница в scope, а не запросы), то foreign fetch позволяет контролировать запросы на свой домен. Допустим, обычное событие fetch будет срабатывать при запросе за библиотекой на CDN, а foreignFetch будет срабатывать при всех запросах за этой библиотекой на любых сайтах! Это любопытная возможность может быть использована, например, службами аналитики.
Тестирование
С написанием тестов на сервис-воркеры есть определённые сложности. Составление теста не так просто: если мы хотим проверить оффлайновый режим, то нужно как-то эмулиовать ошибки сети, если хотим проверить обновление — нужно подменять файл новым и тому подобное.
Дополнительные проблемы также состоят в том, что в текущий момент «безголовые» браузеры не поддерживают сервис-воркеры, а значит, нужны настоящие.
Есть стоящая статья на тему тестирования сервис-воркеров. В ней есть ссылки и на пару инструментов: sw-unit-test-sample и platinum-sw (элемент для Polymer, в нём есть также пара тестов). В статье также описан интересный приём: создание ифрейма для того, чтобы он контролировался тестируемым сервис-воркером. Вообще говоря, у элементов iframe и object есть другая особенность: запросы за ними и их содержимым идут в обход текущего сервис-воркера страницы, используя собственные сервис-воркеры.
То, что caches доступно на самой странице, может быть полезно при тестировании для очистки и проверки содержимого кеша.
Важный нюанс при работе автотестов — определение момента, когда сервис-воркер контролирует страницу и может перехватывать запросы. Простой navigator.serviceWorker.ready не всегда является верным решением — ready срабатывает в момент активации сервис воркера, но до того, как закончится выполнение clients.claim(). Более подробно описано здесь, как одно из решений — слушать событие controllerchange.
Обновление сервис-воркера
Есть несколько нюансов при обновлении сервис-воркеров, на которые стоит обратить внимание.
Несмотря на поддержку кеширующих заголовков при запросе скрипта сервис-воркера, браузеры уменьшают время жизни кеша до 24 часов. Сделано это для того, чтобы случайно не оставить сайт у пользователя в убитом состоянии на большой промежуток времени. Вот хороший ответ на StackOverflow про кеширование.
Другой нюанс: обновление срабатывает, только если сам скрипт сервис-воркера обновился, и определение этого происходит побайтово. Из этого следует, что обновление файлов, которые подключены через importScripts, не приведёт к обновлению самого сервис-воркера.
При обновлении часто добавляются в кеш из сети какие-то файлы. Но при этом работает браузерный кеш! Как и при вызовах fetch внутри сервис-воркера. Нужно либо быть уверенным, что файлы не поменялись (например, включать версию/хеш в название файла), либо загружать ресурсы в обход кеша. Чтобы загружать ресурсы в обход кеша, можно или руками звать fetch и потом добавлять ответ в кеш (не забывая проверять response.ok, например), или использовать опцию cache: ‘no-cache’ Request’а (пока работает только в Firefox Nightly). И то и то описано в статье Jake Archibald.
Также стоит упомянуть, что запрос за скриптом сервис-воркера при обновлении идёт в обход обработчика события fetch текущего сервис-воркера.
Визуализация работы сервис-воркеров
Доброго времени суток, друзья!
Вероятно, многие из вас слышали о таком новшестве в экосистеме JavaScript, как сервис-воркеры (Service Workers), которые являются ключевым элементом современной веб-разработки. Сервис-воркеры становятся все более востребованными, в первую очередь, благодаря популярности прогрессивных веб-приложений (Progressive Web Applications — PWA).
Когда я впервые услышал о них, я задался вопросом: «Когда мы должны использовать сервис-воркеры? В каким сценариях или контексте мы можем их использовать?»
В данной статье мы рассмотрим несколько практических примеров использования сервис-воркеров, что впоследствии, смею надеяться, сделает счастливыми ваших пользователей.
Полагаю, прежде чем разбирать практические примеры, необходимо хотя бы в общих чертах рассмотреть теоретические основы работы сервис-воркеров. Для начинающих разработчиков это послужит хорошим подспорьем в дальнейших начинаниях.
Что есть сервис-воркер?
Серсис воркер — это скрипт, запускаемый браузером в фоновом процессе. Помните, что сервис-воркер совершенно не зависит от страницы, с которой он взаимодействует или которой он служит (to serve — служить).
По сути, сервис-воркер представляет собой прокси сервер между веб-приложением, браузером и сетью.
Сервис-воркеры позволяют веб-приложениям работать подобно нативным приложениям.
Несколько фактов о сервис-воркерах
Как сервис-воркеры работают? Беглый взгляд
Сервис-воркеры позволяют перехватывать запросы к серверу и кешировать эти запросы с целью повышения производительности приложений. Таким образом, повышение производительности обеспечивается благодаря кешированию всего контента.
Но лучше один раз увидеть, так что вот вам изображение, показывающее работу сервис-воркера:
Жизненный цикл сервис-воркера
Как я упоминал ранее, сервис-воркеры работают независимо от управляющей страницы. Если вы хотите установить сервис-воркер в своем приложении, первым делом нужно его зарегистрировать.
После этого браузер, запустивший установку сервис-воркера, переходит в фоновый режим:
Самые распространенные случаи использования
Теперь, когда мы знаем, как работают сервис-воркеры, настало время поговорить о том, где они используются.
Кеширование
Как отмечалось выше, сервис-воркеры могут использоваться для кеширования. Вот некоторые примеры:
Веб-пуш (Web Push)
Веб-пуш позволяет приложениям отправлять пуш-уведомления и отображать контент, получаемый в ответ на эти уведомления.
Более сложные примеры использования
API аналитики
У меня есть приложение. И я хочу добавить в него возможность следить за использованием приложения. Для этого я беру синхронное API для обновления собранных данных время от времени.
Балансировщик загрузки
Допустим, вы хотите иметь возможность выбирать лучшего провайдера контента, опираясь на показатели работы сервера. В этом случае вам нужен сервис-воркер для перехвата запросов и осуществления выбора.
Я настоятельно рекомендую вам посетить ServiceWorke.rs для более подробного изучения сервис-воркеров.
Отрабатываем навыки
Как я всегда говорю: «Хочешь научиться плавать — лезь в воду». Изучение теории — вещь замечательная, но пока не испачкаешь руки, ничему не научишься.
Регистрация сервис-воркера
Если мы вновь обратимся к иллюстрации жизненного цикла сервис-воркера, то увидим, что перво-наперво нам необходимо его установить. Чтобы это сделать нам нужно его зарегистрировать.
В работе сервис-воркера можно убедиться, перейдя по адресу: Chrome://inspect/#service-workers.
Что дальше?
Теперь нам нужно закешировать все файлы. Мы можем выбирать файлы для кеширования. Вот как это выглядит:
Вот что здесь происходит:
Удаляем неиспользуемый кеш
Далее нам необходимо удалить старые версии кеша:
Получение ответа
Ничто из приведенного выше не имеет смысла, если у нас нет возможности получить закешированный контент.
Его можно получить с помощью обработчика события «fetch»:
Кто ты такой, Service Worker?
Service Worker: Я программируемый сетевой проксификатор.
Service Worker звучит круто, но я не очень то понимаю что это
В июле 2015 я участвовала в конференции по JavaScript, проходившей в городе Остин, штат Техас. На сцене — Джейк Арчибальд, которого тогда я знала как забавного британского парня, любителя пошутить на “туалетную тему” 🚽. Уже потом я поняла, что он вполне себе “важный чувак” и является одним из разработчиков спецификации Service Worker’ов.
И вот по ходу истории об UX-откровении, настигнувшем его в общественном туалете, Джейк рассказал залу о новой штуке, названной Service Worker. Штуке, позволяющей вашему веб-сайту вести себя как нативное приложение (по крайней мере тогда я поняла его именно так).
То, о чем он говорил, звучало невероятно, и мне захотелось попробовать технологию на своем проекте. Сначала было немного трудно понять что это… Это не библиотека, не новый HTML элемент и даже не новый JavaScript синтаксис, а такие термины как “кэш” или “прокси” всегда приводили меня в замешательство. Пытаясь разобраться в принципах работы Service Worker’а, я делала пометки на бумаге, и мне в голову пришла идея сравнить его с “пришельцем, которого вы приглашаете пожить в вашем браузере”. Звучит странно? Тогда давайте попробуем разобраться.
S ervice Worker — пришелец во вселенной веб-браузера.
Представьте: ваш браузер — это планета (наподобие Земли), частица большой галактики вашего компьютера. Люди на этой планете разговаривают на своих языках, таких как HTML, CSS и JavaScript, благодаря которым они формируют сообщества — веб страницы.
И если вы веб-разработчик, вы должны хорошо разбираться как функционируют эти сообщества: начиная от их разнообразных элементов и DOM дерева и заканчивая режимами обновления данных на вашем сайте.
На этой планете (в браузере) был придуман способ общения с внешним миром, который позволил запрашивать информацию из других галактик (серверов). Его назвали Hyper Text Transfer Protocol. Именно так ваша планета-браузер превратилась в копилку милых картинок с котятами и ненужных твитов. И именно так она смогла привлечь к себе миллионы постоянных пользователей.
HTTP похож на невероятную волшебную вещицу, однако, чтобы она работала, вам нужен Интернет. Представим его как длинный многоколенчатый трубопровод. Интернет обеспечивает нам необходимое сообщение с удаленными серверами-галактиками. Длина такого трубопровода зависит от того, сколько вы платите обслуживающей организации (интернет-провайдеру), и от качества инфраструктуры в вашем регионе. Если ваша труба узкая или слишком длинная, то и данные из других галактик поступают на вашу планету дольше.
Но дело в том, что Интернет порой оказывается и вовсе недоступным для вашего браузера. В такие периоды ваша планета возвращается в доисторическую эпоху, и никакие из современных вещей вам не доступны, а ваш браузер показывает картинки динозавров, как напоминание о “старых добрых”.
Но подождите! Service Worker уже здесь, чтобы помочь!
Три вещи, которые следует знать о вашем новом приятеле.
Итак, какого типа работу может выполнить для вас Service Worker?
1. Взаимодействие с кэшем
Вы можете попросить Service Worker отслеживать fetch events и сохранять определенные ресурсы в кэше. Позже, когда эти ресурсы понадобятся, он передаст их вашему сайту, а делать внешний HTTP-запрос будет уже не нужно. Таким образом, если необходимые данные предварительно закэшированы, браузер сможет показывать контент веб-страниц даже при отсутствии интернет-подключения.
2. Push-уведомления
Благодаря магии, по которой Service Worker работает даже при выключенном браузере, вы можете всегда быть в курсе, получая push-уведомления.
3. Фоновая синхронизация
Активность при закрытом браузере означает еще и то, что Service Worker будет работать, не отвлекая внимания пользователя на текущие процессы. Скажем, вы используете веб-страницу, будучи offline, но вам необходимо отправить файл. Так вот, Service Worker сам отправит файл на сервер, когда интернет станет доступен снова.
Service Workers
В этой статье я хотел бы поговорить о Service Workers (SW). SW позволяют нам сделать наше приложение готовым к работе в автономном режиме, чтобы оно работало, даже если у нас нет подключения к Интернету. Они также позволяют нам использовать множество других расширенных функций, таких как push-уведомления или фоновая синхронизация. SW продолжает работать даже после закрытия браузера, то есть Service Workers продолжают работать. Это фоновый процесс. Итак, давайте зарегистрируем нашего первого Service Worker’a.
(В этой статье я реализую функциональность, связанную с SW, на простом JS, поскольку код написан на простом JS, мы можем интегрировать в любые JS-фреймворки, такие как Angular, React или Vue)
В качестве первого шага добавим файл sw.js в корневую папку проекта. В app.js мы должны проверить, доступен ли SW в навигаторе, то есть поддерживаются ли SW данным браузером. Теперь, когда мы знаем, что SW доступны, мы можем выполнить метод navigator.serviceWorker.register (), указывая путь к файлу, в котором находится наш SW, чтобы его зарегистрировать. Этот метод фактически возвращает Promise. Итак, чтобы получить информацию, как только это будет сделано, мы можем присоединиться к нему.
Поскольку мы зарегистрировали нашего первого SW, давайте добавим наш первый прослушиватель событий. Как я уже сказал, SW работают в фоновом режиме. Но я не упомянул одну вещь, что все они связаны с обработкой событий. Чтобы прикрепить слушателей событий к SW, мы, прежде всего, должны обратиться к нему с помощью ключевого слова self, что в основном означает «предоставь мне доступ к SW», а затем мы можем выполнить метод addEventListener (). SW надают доступ к специальному набору событий, например, к событию установки, которое запускается, когда браузер устанавливает Service Worker’a. Здесь мы выполняем функцию и получаем объект события, который автоматически передается в функцию браузером, и этот объект предоставляет нам информацию о событии установки. Как мы видим, наш Service Worker успешно установлен.
Теперь посмотрим, действительно ли эти файлы загружены в кеш-память.
Выражение event.respondWith () позволяет нам перезаписывать данные, которые отправляются обратно. Вы можете думать о Service Worker’е как о сетевом прокси, по крайней мере, если мы используем здесь событие fetch. Таким образом, каждый исходящий запрос на выборку проходит через Service Worker, как и каждый ответ. То есть, если мы ничего не делаем, ответ просто не передается. Выражение cashes.match () позволяет нам проверить, кэширован ли уже данный запрос. Если это так, он вернет кешированный ответ. Мы не делаем сетевой запрос, мы перехватываем запрос и не выдаем новый, вместо этого мы просто смотрим на то, что мы хотели запросить, и видим, есть ли оно в кеше и если есть, мы возвращаем его обратно. С другой стороны, если мы не находим его в кеше, мы хотим вернуть запрос на выборку там, где мы обращаемся или где мы просто продолжаем исходный запрос, поэтому вертаем fetch (event.request). После всех этих изменений мы наконец можем использовать наше веб-приложение в автономном режиме.
Как видите, наше веб-приложение содержит диаграмму с некоторыми статическими данными, и при нажатии кнопки «ПОЛУЧИТЬ ДАННЫЕ» ничего не происходит. Теперь я хочу сделать так, чтобы нажав эту кнопку, мы получили некоторые статистические данные, отобразили их на диаграмме и сохранили эти данные в кеше. Таким образом, мы реализуем динамическое кеширование. Итак, приступим. Допустим, у нас есть эндпоинт, который возвращает статистические данные о том, сколько пользователей посетили наш сайт. Итак, теперь мы должны взять эти данные и отобразить их на графике.
Как и раньше, я добавлю решение, а затем объясню, как оно работает.
Сначала нам нужно проверить тег события. Затем я использую event.waitUntil (), как и раньше, это просто позволяет мне убедиться, что событие не завершилось преждевременно. Затем мы получаем данные, которые хранятся в indexedDB (используя вспомогательную функцию из utility.js), перебираем их, отправляем post запрос для каждого из сохраняемых фрагментов данных, а затем удаляем их из indexedDB, если мы успешно отправили их на сервер. Вот и все. Давайте теперь попробуем это. Чтобы проверить эту функциональность, мы должны перейти в автономный режим в нашем браузере, нажать кнопку «POST DATA» и затем снова выйти в онлайн.
После нажатия кнопки «POST DATA», когда мы не в сети, ничего не происходит, но когда подключение восстанавливается, мы видим, что синхронизация была выполнена.
И чтобы подтвердить, что данные действительно были отправлены на сервер, нам сначала нужно удалить наш запрос на получение из динамического кеша и нажать кнопку «ПОЛУЧИТЬ ДАННЫЕ».