Какова цель SwUpdate.activateUpdate() в Angular?

#angular #service-worker #progressive-web-apps

#angular #service-worker #progressive-веб-приложения

Вопрос:

В документации Angular приведен следующий пример активации обновления SW:

 constructor(updates: SwUpdate) {
  updates.available.subscribe(event => {
    if (promptUser(event)) {
        updates.activateUpdate().then(() => document.location.reload());
    }
  });
}
  

Из того, что я наблюдаю, самого вызова недостаточно для активации новой версии, необходима перезагрузка. Однако document.location.reload() достаточно даже без activateUpdate() вызова.

Какова цель activateUpdate() вызова? Зачем вообще его вызывать, когда достаточно перезагрузки?

Комментарии:

1. Нашли ли вы ответ на этот вопрос?

Ответ №1:

Некоторая информация о том, что делает Angular ServiceWorker под капотом:

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

Это поведение немного отличается от того, как обычно работают ServiceWorkers. Он предназначен для предоставления последней версии новым клиентам, но не для взлома существующих (путем предоставления им нового контента, который не предназначен для работы со старым кодом HTML / CSS / JS, который они уже используют).


Теперь вернемся к activeUpdate() :

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


Достаточно ли простой перезагрузки?

Это в основном зависит от того, как браузеры назначают Client.id при перезагрузках. Если браузер назначает новый идентификатор вкладке при перезагрузке, то SW в любом случае будет обслуживать последнюю версию, поэтому swUpdate.activeUpdate() в этом нет необходимости. Если, с другой стороны, браузер сохраняет тот же идентификатор клиента, то SW будет обслуживать старую версию без swUpdate.activeUpdate() .

В настоящее время Chrome, похоже, присваивает новый идентификатор (и, следовательно, activeUpdate() не нужен перед перезагрузкой). Я не смог найти что-то убедительное в спецификации SW, поэтому я не уверен, соответствует ли это спецификации и все ли браузеры делают то же самое. (Также возможно, что в прошлом браузеры вели себя по-другому, что activeUpdate() делало необходимым, но с тех пор спецификация / браузеры были обновлены, что делает их излишними, если вы планируете перезагрузку.)


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

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

Например, вы могли бы:

  1. Немедленно активируйте обновление (если вы уверены, что ваше приложение справится с этим) и не перезагружайте.
  2. Показать уведомление о том, что доступно обновление, и позволить пользователю щелкнуть, чтобы перезагрузить (и, следовательно, обновить).
  3. Сообщите приложению, что доступно обновление, и оно автоматически перезагрузится при следующей навигации в приложении. (Это то, что мы делаем вhttps://angular.io / кстати.)

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


РЕДАКТИРОВАТЬ:
КСТАТИ, если у вас есть предложения о том, как можно улучшить документацию, пожалуйста, откройте проблему (или, что еще лучше, отправьте запрос на извлечение)!

Комментарии:

1. Спасибо за информативный ответ. Можете ли вы объяснить, как закодировать этот третий вариант перезагрузки страницы при следующей навигации в приложении?

2. Также о первом (обновление немедленно). Означает ли это, что часть приложения / модулей / служб будет иметь новый код, если да, то какие части? Казалось бы, хороший вариант просто сказать: страница была открыта, и обновление готово, поэтому, поскольку пользователь только что прибыл, давайте активируем новую версию (если это безопасно с точки зрения кода).

3. Что касается первого вопроса, соответствующий код из angular.io является github.com/angular/angular/blob /… , github.com/angular/angular/blob /… и github.com/angular/angular/blob /… .

4. Я не понимаю второй вопрос:D

5. Спасибо @gkalpak за этот замечательный ответ. Многому научился, и на многие вопросы также были даны ответы.

Ответ №2:

Из кода github я понимаю, что activateUpdate() отправит postMessage() в поток service worker, чтобы сообщить ему о новых данных и статусе, и как только обещание будет выполнено (поток service worker знает об этом), перезагрузите страницу.

https://github.com/angular/angular/blob/7.2.11/packages/service-worker/src/update.ts#L57-L64

 activateUpdate(): Promise<void> {
    if (!this.sw.isEnabled) {
      return Promise.reject(new Error(ERR_SW_NOT_SUPPORTED));
    }
    const statusNonce = this.sw.generateNonce();
    return this.sw.postMessageWithStatus('ACTIVATE_UPDATE', {statusNonce}, statusNonce);
}
  

https://github.com/angular/angular/blob/master/packages/service-worker/src/low_level.ts#LC105

 postMessageWithStatus(type: string, payload: Object, nonce: number): Promise<void> {
    const waitForStatus = this.waitForStatus(nonce);
    const postMessage = this.postMessage(type, payload);
    return Promise.all([waitForStatus, postMessage]).then(() => undefined);
}
  

Комментарии:

1. Это все еще не объясняет, почему, в чем разница с простой перезагрузкой страницы?