Отмена дребезга асинхронной работы внутри обработчика событий сервисного работника

Использование отклоненных функций lodash в ServiceWorker допустимо для Firefox. Они ждут назначенного тайм-аута, и таймер сбрасывается, если функция, от которой отказались, вызывается снова.

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

Кто-нибудь сталкивался с этой проблемой? Любые обходные пути?

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


person Eduardo Poço    schedule 26.04.2021    source источник


Ответы (1)


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

  • запланировать эту работу изнутри ExtendableEvent и
  • оберните работу, передав обещание о ее завершении методу waitUntil() этого ExtendableEvent.

(FetchEvent — это ExtendableEvent.)

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

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

Если оставить в стороне фактическую реализацию возвращающего обещание debounceWithPromises(), общая структура будет выглядеть так:

self.addEventListener('fetch', (event) => {
  if (/* some criteria is met */) {
    // As soon as the promise passed to respondWith() resolves,
    // the response will start being fed to the client.
    event.respondWith(generateResponse(event);

    // Independent of the response generation, the promise returned
    // by the hypothetical debounceWithPromises() will keep the
    // service worker alive until it resolves or rejects (or until a
    // browser-specific maximum lifetime is reached).
    event.waitUntil(debounceWithPromises(logStats));
  }
});
person Jeff Posnick    schedule 26.04.2021
comment
Теперь все понятно, но я думал убитый сервисворкер в итоге не отправит аналитику, а не пропустит время ожидания - person Eduardo Poço; 26.04.2021
comment
Я не уверен на 100% в этой разнице в поведении, но полагаться на event.waitUntil() в таких вещах по-прежнему важно. - person Jeff Posnick; 26.04.2021