Таймер с уведомлениями с использованием сервисного работника - PullRequest
0 голосов
/ 06 ноября 2018

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

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

index.html

<!DOCTYPE html>
<html>
<body>
<button onclick="notify();">notify</button>
</body>
<script>
  function notify() {
    const items = ["First", "End of the break", "Second"];
    const options = { data: items };

    if ('serviceWorker' in navigator) {
      Notification.requestPermission()
        .then(() => navigator.serviceWorker.register('sw.js'))
        .then(() => navigator.serviceWorker.ready
        .then((s) => {
          s.showNotification('Click to begin', options);
        }))
      .catch(e => console.log(e.message));
    }
  }
</script>
</html>

sw.js

let data = [];
let num = 0;

self.onnotificationclick = (event) => {
  event.notification.close();
  if (event.notification.data) {
    ({ data } = event.notification);
  }

  if (num < data.length) {
    setTimeout(() => {
      self.registration.showNotification(data[num]);
      num += 1;
    }, num % 2 === 0 ? 1 : 3000);
  }
};

Я знаю, что не должно быть setTimeout в sw.js, но это наиболее близко к точке, которую я хочу достичь.

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

1 Ответ

0 голосов
/ 06 ноября 2018

(Это длинный ответ, так как есть несколько вопросов, которые нужно обсудить с вашим вопросом)

Конструкция сервисных работников заключается в том, что вы должны выполнять свою работу как можно быстрее и возвращать управление браузеру. Это делается с помощью функции event.waitUntil(<promise>), когда вы сообщаете браузеру, что заняты, не выполняя обещание, которое вы передаете.

В приведенном выше примере вы не используете event.waitUntil(), который может продлить жизнь работнику службы.

Например, вы можете попробовать:

self.onnotificationclick = (event) => {
  event.notification.close();
  if (event.notification.data) {
    ({ data } = event.notification);
  }

  if (num < data.length) {
    event.waitUntil(new Promise(function(resolve, reject) {
        setTimeout(() => {
            self.registration.showNotification(data.num);
            resolve();
        }, 3000);
    })
  }
};

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

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

Еще одно примечание: к использованию глобальных переменных в сервисном работнике следует относиться с осторожностью. Как я уже сказал, работника службы можно часто запускать и прерывать, поэтому чтение / запись из indexDB может быть более подходящим для хранения информации.

...