Обучение и практика Service Worker (1) — автономный кэш

внешний интерфейс сервер браузер Webpack
Обучение и практика Service Worker (1) — автономный кэш

чтоService Worker

Service WorkerПо существу действует как прокси-сервер между веб-приложением и браузером, а также может действовать как прокси-сервер между браузером и сетью, когда сеть доступна. Они предназначены (среди прочего) для обеспечения эффективного автономного взаимодействия, перехвата сетевых запросов и выполнения соответствующих действий в зависимости от того, доступна ли сеть и находится ли обновленный ресурс на сервере. Они также разрешают доступ к push-уведомлениям и фоновой синхронизации.API.

  • Service WorkerСуть - этоWeb Worker, который не зависит отJavaScriptосновной поток, поэтому он не может получить прямой доступDOM, и вы не можете получить прямой доступwindowобъект, однакоService Workerможет получить доступnavigatorобъектов или путем передачи сообщений (postMessage)а такжеJavaScriptОбщение основного потока.
  • Service Workerэто веб-прокси, который контролируетWebВсе сетевые запросы для страницы.
  • Service WorkerИмеет свой жизненный цикл, используйте его правильноService WorkerГлавное — гибко управлять его жизненным циклом.

Service Workerроль

  • для кеширования браузера
  • Не в сетиWeb APP
  • сообщение

Service Workerсовместимость

Service Workerэто расширенная функция современных браузеров, основанная наfetch API,Cache Storage,Promiseдр., из нихCacheпри условииRequest / ResponseМеханизм хранения пар объектов,Cache Storageхранить несколькоCache.

Пример

в пониманииService WorkerПрежде чем принцип, давайте посмотрим на параграфService WorkerПример:

self.importScripts('./serviceworker-cache-polyfill.js');

var urlsToCache = [
  '/',
  '/index.js',
  '/style.css',
  '/favicon.ico',
];

var CACHE_NAME = 'counterxing';

self.addEventListener('install', function(event) {
  self.skipWaiting();
  event.waitUntil(
    caches.open(CACHE_NAME)
    .then(function(cache) {
      return cache.addAll(urlsToCache);
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
    .then(function(response) {
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  );
});


self.addEventListener('activate', function(event) {
  var cacheWhitelist = ['counterxing'];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

Далее начинается анализ по разделам, раскрываяService WorkerТайна:

polyfill

Сначала посмотрите на первую строку:self.importScripts('./serviceworker-cache-polyfill.js');, представлено здесьCache APIодин изpolyfill,этоpolyfillПоддержка делает его также доступным в браузерах более ранних версий.Cache Storage API. хочу достичьService Workerфункция, как правило, должна соответствоватьCache APIПроксировать сетевые запросы в кеш.

существуетService Workerнить, использоватьimportScriptsпредставлятьpolyfillСкрипт для совместимости с браузерами более ранних версий.

Cache Resources List And Cache Name

После этого используйтеurlsToCacheСписок для объявления статических ресурсов, которые необходимо кэшировать, а затем используйте переменнуюCACHE_NAMEопределить текущий кешCache Storage Name, что можно понимать какCache StorageЯвляетсяDB,а такжеCACHE_NAMEявляетсяDBимя:

var urlsToCache = [
  '/',
  '/index.js',
  '/style.css',
  '/favicon.ico',
];

var CACHE_NAME = 'counterxing';

Lifecycle

Service Workerнезависимый от браузераJavaScriptОсновной поток имеет свой независимый жизненный цикл.

Если вам нужно установить на сайтService Worker, тебе следуетJavaScriptПредставлен в основном потоке с использованием следующего кодаService Worker.

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js').then(function(registration) {
    console.log('成功安装', registration.scope);
  }).catch(function(err) {
    console.log(err);
  });
}

Здесь мы должны обратить вниманиеsw.jsПуть к файлу, в моем примере под текущим корнем домена, значит,Service WorkerОн имеет то же происхождение, что и веб-сайт, и может действовать как прокси для всех запросов текущего веб-сайта, еслиService Workerбыть зарегистрированным в/imaging/sw.jsdown, это может быть только прокси/imagingследующие сетевые запросы.

можно использоватьChromeконсоль, просмотреть текущую страницуService Workerусловие:

После завершения установкиService WorkerПройдет следующий жизненный цикл:

  1. скачать(download)
  2. Установить(install)
  3. активация(activate)
  • первый визит пользователяService WorkerПри управлении веб-сайтом или страницейService Workerбудут загружены немедленно. По крайней мере после каждого24Он будет загружаться один раз в час. Он может загружаться чаще, но каждый24Час гарантированно будет загружен один раз, чтобы плохие скрипты не действовали в течение длительного времени.

  • После завершения загрузки запустите установкуService WorkerНа этапе установки обычно ресурсы, которые нам нужны для кэширования некоторых статических данных, предварительно объявленных, в нашем примере,urlsToCacheПредварительно объявить.

  • После завершения установки начнется активация, и браузер попытается загрузитьService WorkerПосле того, как файл скрипта будет успешно загружен, он будет таким же, как ранее кэшированныйService WorkerФайл скрипта сравнивается, если он сравнивается с предыдущимService WorkerФайлы скриптов разные, что доказываетService Workerбыл обновлен и сработаетactivateмероприятие. Полная активация.

Как показано на рисунке, дляService WorkerПримерный жизненный цикл:

install

После установки попробуйте закешировать некоторые статические ресурсы:

self.addEventListener('install', function(event) {
  self.skipWaiting();
  event.waitUntil(
    caches.open(CACHE_NAME)
    .then(function(cache) {
      return cache.addAll(urlsToCache);
    })
  );
});

первый,self.skipWaiting()Выполнить, скажите браузеру пропустить стадию ожидания напрямую и удалить просроченныеsw.jsизService Workerскрипт, сразу начните пытаться активировать новыйService Worker.

затем используйтеcaches.openоткрыть одинCache, после открытия пройтиcache.addAllПопробуйте кэшировать наши предварительно объявленные статические файлы.

мониторfetchЗапросы прокси-сети

Все сетевые запросы на страницу пройдутService Workerизfetchтриггер события,Service Workerпройти черезcaches.matchпопробовать изCacheНайдите кеш в кеше, если кеш попадет, то сразу вернётся в кешresponse, в противном случае создайте настоящий сетевой запрос.

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
    .then(function(response) {
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  );
});

Если нам нужно отправить запрос наCache Storageдобавить новый кеш вcache.putдля добавления, см. следующий пример:

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
    .then(function(response) {
      // 缓存命中
      if (response) {
        return response;
      }

      // 注意,这里必须使用clone方法克隆这个请求
      // 原因是response是一个Stream,为了让浏览器跟缓存都使用这个response
      // 必须克隆这个response,一份到浏览器,一份到缓存中缓存。
      // 只能被消费一次,想要再次消费,必须clone一次
      var fetchRequest = event.request.clone();

      return fetch(fetchRequest).then(
        function(response) {
          // 必须是有效请求,必须是同源响应,第三方的请求,因为不可控,最好不要缓存
          if (!response || response.status !== 200 || response.type !== 'basic') {
            return response;
          }

          // 消费过一次,又需要再克隆一次
          var responseToCache = response.clone();
          caches.open(CACHE_NAME)
            .then(function(cache) {
              cache.put(event.request, responseToCache);
            });
          return response;
        }
      );
    })
  );
});

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

activate

Service WorkerВсегда есть день, который нужно обновить.С итерацией версии, однажды нам нужно выпустить функции новой версии онлайн.В это время нам нужно устранить старый кеш и старый кеш.Service Workerа такжеCache StorageКак это устранить?

self.addEventListener('activate', function(event) {
  var cacheWhitelist = ['counterxing'];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});
  1. Сначала есть белый список, в белом спискеCacheне устраняется.
  2. проходить послеcaches.keys()получить всеCache Storage, поставить не в белый списокCacheнеиспользование.
  3. устаревшее использованиеcaches.delete()метод. он получаетcacheNameв качестве аргумента удалитеcacheNameВсе тайники.

sw-precache-webpack-plugin

sw-precache-webpack-pluginЯвляетсяwebpack plugin, который можно настроить вwebpackГенерировать то, что мы хотим, при упаковкеsw.jsизService Workerсценарий.

Простейшая конфигурация выглядит следующим образом:

var path = require('path');
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');

const PUBLIC_PATH = 'https://www.my-project-name.com/';  // webpack needs the trailing slash for output.publicPath

module.exports = {

  entry: {
    main: path.resolve(__dirname, 'src/index'),
  },

  output: {
    path: path.resolve(__dirname, 'src/bundles/'),
    filename: '[name]-[hash].js',
    publicPath: PUBLIC_PATH,
  },

  plugins: [
    new SWPrecacheWebpackPlugin(
      {
        cacheId: 'my-project-name',
        dontCacheBustUrlsMatching: /\.\w{8}\./,
        filename: 'service-worker.js',
        minify: true,
        navigateFallback: PUBLIC_PATH + 'index.html',
        staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
      }
    ),
  ],
}

в исполненииwebpackПосле упаковки файл с именемservice-worker.jsфайл для кэшированияwebpackУпакованные статические файлы.

один из самых простыхПример.

Service Worker Cache VS Http Cache

ПростиHttp Headerкеш,Service WorkerСотрудничатьCache StorageЕсть у него и свои преимущества:

  1. Кэш и обновление сосуществуют: каждый раз, когда версия обновляется, с помощьюService WorkerВы можете использовать кеш для немедленного возврата, но в то же время вы можете инициировать запрос, чтобы проверить, есть ли обновление новой версии.
  2. Ненавязчивый:hashЗначение действительно уродливое.
  3. Не легко смывается:HttpКэш легко очищается и срок его действия истекает, в то время какCache Storageне легко смывается. Также нет срока годности.
  4. Офлайн: с помощьюService WorkerВозможен оффлайн доступ к приложениям.

Но недостаток в том, что потомуService Workerзависит отfetch API, зависит отPromise,Cache StorageПодождите, совместимость не очень.

позже

Эта статья просто суммируетService WorkerОсновное использование и использованиеService WorkerОднако простой способ кэширования на стороне клиентаService Workerнамного больше, например:Service WorkerДля автономных приложений, для загрузки сетевых приложений (см.push-notifications)Ждать.

даже с помощьюService Worker, кешировать интерфейс, в моем проекте это не так уж и сложно. Однако преимущество кэширования интерфейса заключается в том, что оно поддерживает автономный доступ, и мы также можем нормально обращаться к нашему веб-сайту в автономном режиме.Webзаявление.

Cache Storageа такжеService Workerвсегда неразделим.Service WorkerЛучшее использование на самом деле сотрудничатьCache StorageЗаймитесь автономным кэшированием. посредствомService Worker, вы можете легко управлять сетевыми запросами и применять разные стратегии для разных сетевых запросов. Например дляCacheстратегии, на самом деле, есть много ситуаций. Например, сетевой запрос может использоваться первым, а кеш может использоваться при сбое сетевого запроса, или кеш и сетевой запрос могут использоваться одновременно.С одной стороны проверяется запрос, а с другой с другой стороны проверяется кеш, а потом будет использован тот, кто быстрее.