Повторяющиеся экземпляры setInterval, запущенные из Service Worker после каждой загрузки приложения - PullRequest
0 голосов
/ 04 февраля 2020

У меня есть Service Service Worker, который регистрируется при запуске моего приложения, и внутри него вызывается функция init () для запуска фоновых процессов, в частности, setInterval, который вызывается каждую минуту. В целях тестирования я отправляю уведомление о том, что оно запускается через каждый интервал.

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

Например, я открываю приложение с очищенным кэшем и получаю одно уведомление в минуту. Отлично. Я обновляю sh на той же странице, а затем получаю два уведомления в минуту (по мере нажатия на ссылку refre sh). Если я открою новую вкладку с тем же приложением, я получу третий экземпляр setInterval, начинающийся в этот момент, и если я переименую sh эту вкладку тоже, я получу другой экземпляр, et c, et c.

Мне стыдно, что я не могу найти ответ, но я потратил слишком много времени на чтение и тестирование, но никуда не попал. Как мне остановить это поведение и что на самом деле здесь происходит?

Есть ли событие Service Worker, которое я могу использовать для вызова clearInterval при обновлении вкладки или открытии новой вкладки?

ОБНОВЛЕНИЕ 2020-02-04

Вот упрощенная версия того, что я делаю. Кроме того, я использовал глобальное пространство для установки и очистки интервала, который обеспечивает перезагрузку отдельных вкладок. На полпути!


function init() {
  // Clear the interval if it already exists on the global object
  if (self.globalObj.initInterval) self.clearInterval(self.globalObj.initInterval);
  // Set the interval to the global object
  self.globalObj.initInterval = self.setInterval(() => {
    // Notify the user every minute
    if (self.Notification.permission === 'granted') {
      self.registration.showNotification('You\'ve got new messages!', {
        body: 'Click this link to open a new browser window to view your messages.',
      });
    }
  }, 60000);
}

self.addEventListener('message', e => {
  if (e.data === 'init') init();
});

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

Мне может понадобиться откат к Shared Worker, как было предложено, но мы пытаемся использовать Service Workers, поскольку у нас есть поток, который мы используем для всего остального, и я хотел бы найти решение в мире Service Worker.

Спасибо за помощь!

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

После многих испытаний и испытаний, таких как Shared и Web Workers, я смог получить то, что мне нужно, чтобы остаться с Service Workers.

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

self.globalObj = {};

function init(id) {
  // Clear the interval if it already exists on the global object
  if (self.globalObj.initInterval) self.clearInterval(self.globalObj.initInterval);
  // Set the interval to the global object
  self.globalObj.initInterval = self.setInterval(() => {
    // Notify the user every minute
    if (self.Notification.permission === 'granted') {
      const notificationOptions = {
        body: 'Click this link to open a new browser window to view your messages.',
        icon: './images/some-image.png',
      };
      if (id) notificationOptions.tag = id; // Every ID has to be unique; otherwise it won't trigger, but leaving that `tag` prop off, will always trigger a new notification
      self.registration.showNotification('You\'ve got new messages!', notificationOptions);
    }
  }, 60000);
}

self.addEventListener('message', e => {
  if (e.data === 'init') init(e.id);
});

Первая половина ответа: Если вы установите / очистите глобальную переменную, как в этом примере, вы мгновенно решить проблему перезагрузки браузера, потому что у него есть способ очистить ранее сохраненный (я никогда не думал, что интервал может сохраняться через refre sh, но это, безусловно, происходит, и вы должны справиться с этим, как в этом примере!).

Вторая половина ответа: Хотя этот упрощенный c фиктивный демонстрационный код не раскрывает реальный случай использования вызова fetch в течение интервала или отбрасывания интервала и использования Вместо события push в любом случае проблема дублирования кросс-таблиц с уведомлениями решается с помощью свойства tag. Таким образом, в обычном случае использования, будь то fetch с интервалом или push, вам нужно передать уникальную строку tag. Если свойство tag отсутствует, вы будете получать уведомления по запросу со всех вкладок, но если вы укажете строковое значение tag, только ОС одно будет отправлено в ОС. Это означает, что только одна из вкладок получит уведомление о фактической публикации в системе уведомлений ОС. Отлично !, теперь нет дубликатов. НО, поскольку он разрешает только одно уведомление с указанием c tag, ваш следующий fetch или push должен вернуть другой уникальный tag / id, такой как UUID, или, возможно, даже * 1026 Значение * как значение tag, если оно действительно уникально!

? И вот оно! Нет дублированных уведомлений по refre sh и дублированных уведомлений на вкладках.

0 голосов
/ 04 февраля 2020

Это инициализация в коде работника службы или в коде вашего пользовательского интерфейса? Только 1 экземпляр работника службы активен независимо от того, сколько клиентов открыто в области работника службы.

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

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

...