Service Worker: как кэшировать первую (динамическую) страницу - PullRequest
0 голосов
/ 18 апреля 2019

У меня есть это одностраничное приложение с динамическим URL-адресом, созданным с помощью токена, например example.com/XV252GTH, и различных ресурсов, таких как css, favicon и т. Д.

Вот как я регистрирую сервисного работника:

navigator.serviceWorker.register('sw.js');

И в указанном sw.js я предварительно кеширую ресурсы при установке:

var cacheName = 'v1';

var cacheAssets = [
    'index.html',
    'app.js',
    'style.css',
    'favicon.ico'
];

function precache() {
    return caches.open(cacheName).then(function (cache) {
        return cache.addAll(cacheAssets);
    });
}

self.addEventListener('install', function(event) {
    event.waitUntil(precache());
});

Обратите внимание, что страница index.html (которая регистрирует Service Worker) является просто шаблоном, который заполняется на сервере перед отправкой клиенту; поэтому на этом этапе предварительного кэширования я кеширую только шаблон, а не страницу.

Теперь в событии выборки любой запрошенный ресурс, которого нет в кэше, копируется в него:

addEventListener('fetch', event => {
    event.respondWith(async function() {
        const cachedResponse = await caches.match(event.request);
        if (cachedResponse) return cachedResponse;       
        return fetch(event.request).then(updateCache(event.request));
    }());
});

Использование этой функции обновления

function updateCache(request) {
    return caches.open(cacheName).then(cache => {
        return fetch(request).then(response => {
            const resClone = response.clone();
            if (response.status < 400)
                return cache.put(request, resClone);
            return response;
        });
    });
}

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

Вопрос: Как я могу отправить запрос (/XV252GTH) с клиента (страницы, на которой регистрируется работник) на ПО? Я думаю, я могу настроить слушателя в sw.js

self.addEventListener('message', function(event){
    updateCache(event.request)
});

Но как я могу быть уверен, что оно будет выполнено вовремя, то есть отправлено клиентом после завершения установки ПО? Что такое хорошая практика в этом случае?

Ответы [ 2 ]

1 голос
/ 18 апреля 2019

Поправьте меня, если я вас неправильно понял!
Вы предварительно кешируете свои файлы прямо здесь:

var cacheAssets = [
    'index.html',
    'app.js',
    'style.css',
    'favicon.ico'
];

function precache() {
    return caches.open(cacheName).then(function (cache) {
        return cache.addAll(cacheAssets);
    });
}

Должно быть ясно, что вы кешируете шаблон, так как кешируете его раньшесайт строится, и этот подход не ошибается, по крайней мере, не для всех типов файлов.
Например, favicon.ico - это файл, который вы, вероятно, считаете static.Кроме того, он не меняется очень часто или совсем не меняется и не является динамическим, как ваш index.html.
Schema Источник

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

Решением этой проблемы является ответ на ваш вопрос:

Как можноЯ отправляю запрос (/XV252GTH) с клиента (страницы, на которой регистрируется работник) на ПО?

Вместо того, чтобы кэшировать его до установки service-worker, вы хотите его кэшировать, еслизадний конец построил вашу веб-страницу.Вот как это работает:

  1. У вас есть пустой кэш или, по крайней мере, кэш без вашего index.html.
  2. Обычно на сервер отправляется запрос на получениеindex.html.Вместо этого мы делаем запрос в кэш и проверяем, находится ли index.html в кэше, по крайней мере, если вы загружаете страницу в первый раз.
  3. Поскольку в кэше нет совпадений, выполнитезапрос на сервер, чтобы получить его.Это тот же запрос, который будет выполнять страница, если она загрузит страницу в обычном режиме.Итак, сервер создает ваш index.html и отправляет его обратно на страницу.
  4. После получения index.html загрузите его на страницу и сохраните в кеше.

AnПример метода: Stale-while-revalidate: enter image description here

Если доступна кэшированная версия, используйте ее, но получите обновление в следующий раз.

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.open('mysite-dynamic').then(function(cache) {
      return cache.match(event.request).then(function(response) {
        var fetchPromise = fetch(event.request).then(function(networkResponse) {
          cache.put(event.request, networkResponse.clone());
          return networkResponse;
        })
        return response || fetchPromise;
      })
    })
  );
});

Источник

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

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

Это путь.

0 голосов
/ 18 апреля 2019

ОК, я получил ответ от этой страницы : чтобы кэшировать саму страницу, которая регистрирует работника во время активации, просто перечислите всех клиентов ПО и получите их URL (href атрибут).

self.clients.matchAll({includeUncontrolled: true}).then(clients => {
    for (const client of clients) {
        updateCache(new URL(client.url).href);
    }
});
...