В предыдущей статье «Как я заставил свой сайт использовать манифест HTML5«Рассказывает, как использовать Manifest для создания автономного веб-приложения. В результате многие пользователи сети жаловались, что эта вещь устарела, вышла из веб-стандарта и теперь заменена Service Worker. В любом случае, некоторые идеи Manifest еще можно позаимствовать. Автор снова обновил веб-сайт до Service Worker. Если вы используете Chrome и другие браузеры, используйте Service Worker для автономного кэширования. Если вы используете браузер Safari, вы по-прежнему используете Manifest. Читатели могут открыть этот веб-сайт.www.rrfed.comПощупайте, разъединение тоже можно открыть нормально.
1. Что такое сервис-воркер
Service Worker играет ключевую роль в реализации PWA (прогрессивного веб-приложения), инициированного Google. PWA призвано устранить недостатки традиционного веб-приложения:
(1) Нет доступа к рабочему столу
(2) Невозможно использовать в автономном режиме
(3) без толчка
Какова конкретная производительность Service Worker? Как показано ниже:
Service Worker — это поток Service Worker, запущенный в фоновом режиме.На приведенном выше рисунке я открыл две вкладки, поэтому отображаются два Clients, но независимо от того, сколько страниц открыто, только один Worker отвечает за управление. Задача воркера кэшировать какие-то ресурсы, а потом уже перехватывать запросы страниц.Сначала посмотреть есть ли такие в библиотеке кеша.Если есть то взять из кеша и ответить 200. Иначе пойдет в обычный запрос . В частности, Service Worker в сочетании с манифестом веб-приложения может выполнять следующие задачи (это также стандарт обнаружения PWA):
В том числе возможность использования в автономном режиме, возврат 200 при отключении сети, возможность предложить пользователю добавить значок на рабочий стол и т. д.
2. Поддержка сервис-воркеров
Service Worker в настоящее время поддерживается только Chrome/Firfox/Opera:
Safari и Edge также готовятся к поддержке Service Worker.Поскольку Service Worker является стандартом, в котором доминирует Google, он также вынужден подготовить поддержку экологически закрытого Safari.В версии Safari TP можно увидеть:
В Experimental Features уже есть пункт меню для Service Worker, но его нельзя использовать, даже если он открыт, и вам будет выдано сообщение о том, что он не реализован:
Но в любом случае это как минимум показывает, что Safari готов поддерживать Service Worker. Кроме того, видно, что версия Safari 11.0.1, выпущенная в сентябре 2017 года, уже поддерживает WebRTC, так что Safari все еще остается мотивированным ребенком.
Edge также готов к поддержке, поэтому будущее сервис-воркеров очень светлое.
3. Использование сервис-воркеров
Процедура Service Worker заключается в том, чтобы сначала зарегистрировать Worker, а затем запустить поток в фоновом режиме.Вы можете загрузить некоторые ресурсы и кэшировать их при запуске этого потока, а затем прослушивать событие выборки и перехватывать запросы страниц в этом событии. Есть ли в нижнем кеше, если есть, верните напрямую, иначе загрузите нормально. Либо он не кешируется в начале, а копируется копия кеша после каждого запроса ресурса, а потом кеш доступен в следующем запросе.
(1) Зарегистрируйте сервисного работника
Объект Service Worker находится в window.navigator со следующим кодом:
window.addEventListener("load", function() {
console.log("Will the service worker register?");
navigator.serviceWorker.register('/sw-3.js')
.then(function(reg){
console.log("Yes, it did.");
}).catch(function(err) {
console.log("No it didn't. This happened: ", err)
});
});
Зарегистрируйтесь после загрузки страницы.При регистрации передайте ему файл js.Этот файл js является рабочей средой Service Worker.Если регистрация не удалась, будет выброшено исключение.Например,хотя Safari TP имеет этот объект, это вызовет исключение.Используйте, вы можете обработать его в улове. Вопрос здесь в том, зачем вам нужно запускать его в событии загрузки? Поскольку вам нужно запустить дополнительный поток, вы также можете позволить ему загружать ресурсы после запуска. Все это требует ЦП и пропускной способности. Мы должны убедиться, что страница может загружаться нормально, а затем запустить наш фоновый поток. Загрузка страницы создает конкуренцию, что более значимо на недорогих мобильных устройствах.
Еще один момент, на который следует обратить внимание, это то, что Service Worker имеет ту же концепцию пути, что и cookie. установлен в корневой каталог /, все страницы могут получить его. Точно так же, если путь js, используемый при регистрации, — /page/sw.js, то этот сервис-воркер может управлять страницами и ресурсами только по пути /page, но не может обрабатывать те, что по пути /api, поэтому обычно сервис-воркер регистрируется для каталог верхнего уровня, такой как «/sw-3.js» в приведенном выше коде, чтобы этот Service Worker мог взять на себя все ресурсы страницы.
(2) Установка и активация Service Worker
После регистрации будет установлен Service Worker.В это время будет запущено событие установки.В событии установки некоторые ресурсы могут кэшироваться, как показано ниже sw-3.js:
const CACHE_NAME = "fed-cache";
this.addEventListener("install", function(event) {
this.skipWaiting();
console.log("install service worker");
// 创建和打开一个缓存库
caches.open(CACHE_NAME);
// 首页
let cacheResources = ["https://www.rrfed.com/?launcher=true"];
event.waitUntil(
// 请求资源并添加到缓存里面去
caches.open(CACHE_NAME).then(cache => {
cache.addAll(cacheResources);
})
);
});
С помощью вышеуказанных операций создается и добавляется библиотека кеша с именем fed-cache, как показано в консоли Chrome ниже:
API Service Worker в основном возвращает объекты Promise, чтобы избежать блокировки, поэтому используйте запись промисов. При установке вышеописанного Service Worker запрос домашней страницы кэшируется. В работающей среде Service Worker он имеет глобальный объект кешей, который является входом в кеш, и глобальный объект часто используемых клиентов.Клиент соответствует вкладке.
Service Worker может использоваться внутри и, таким образом, получать API, который изолирован и DOM, без объектов окон/документов, вы не можете напрямую манипулировать DOM и не можете напрямую взаимодействовать со страницей, внутри Service Worker не может знать текущую страницу открыть, URL-адрес текущей страницы Что такое управление Service Worker, потому что в настоящее время открыто несколько вкладок, вы можете узнать URL-адрес всех страниц клиентами. Там может быть метод postMessage и Home, передающие сообщения и данные друг другу и, таким образом, осуществляющие контроль.
После завершения установки будет запущено активное событие Service Worker:
this.addEventListener("active", function(event) {
console.log("service worker is active");
});
После активации Service Worker он может прослушивать событие fetch.Мы надеемся, что каждый раз, когда ресурс будет получен, он будет кэшироваться, поэтому нет необходимости сначала генерировать список, как упоминалось в манифесте в предыдущей статье.
Вы можете спросить, разве я не перерегистрировал, не установил и не активировал Service Worker, когда обновлял страницу? Хоть регистрация и настроена заново, перерегистрировать не получится.Обнаруживает, что "sw-3.js" уже зарегистрирован, поэтому повторно не прорегистрируется, и тогда события install и active не сработают, т.к. текущий Service Worker уже находится в активном состоянии. Когда Service Worker необходимо обновить, например, изменить на «sw-4.js» или изменить текстовое содержимое sw-3.js, он будет перерегистрирован, сначала будет установлен новый Service Worker, а затем войти в состояние ожидания, дождаться перезапуска браузера, старый Service Worker будет заменен, а новый Service Worker перейдет в активное состояние.Если вы не хотите ждать перезапуска браузера, вы можете настроить skipWaiting в установить как указано выше:
this.skipWaiting();
(3) Кэшировать после извлечения ресурсов
Следующий код прослушивает событие выборки, чтобы выполнить некоторую обработку:
this.addEventListener("fetch", function(event) {
event.respondWith(
caches.match(event.request).then(response => {
// cache hit
if (response) {
return response;
}
return util.fetchPut(event.request.clone());
})
);
});
Сначала вызовите caches.match, чтобы узнать, есть ли что-то в кеше, есть ли ответ, возвращенный непосредственно в кеш, в противном случае запросите ресурс в обычном режиме и поместите его в кеш. Ключевым значением ресурса в кеше является объект запроса. При сопоставлении запрошенный URL и заголовок должны быть согласованы, чтобы быть одним и тем же ресурсом. Вы можете установить второй параметр ignoreVary:
caches.match(event.request, {ignoreVary: true})
Указывает, что если URL-адрес запроса один и тот же, он считается одним и тем же ресурсом.
util.fetchPut приведенного выше кода реализован следующим образом:
let util = {
fetchPut: function (request, callback) {
return fetch(request).then(response => {
// 跨域的资源直接return
if (!response || response.status !== 200 || response.type !== "basic") {
return response;
}
util.putCache(request, response.clone());
typeof callback === "function" && callback();
return response;
});
},
putCache: function (request, resource) {
// 后台不要缓存,preview链接也不要缓存
if (request.method === "GET" && request.url.indexOf("wp-admin") < 0
&& request.url.indexOf("preview_id") < 0) {
caches.open(CACHE_NAME).then(cache => {
cache.put(request, resource);
});
}
}
};
Следует отметить, что междоменные ресурсы нельзя кэшировать, а response.status вернет 0. Если междоменные ресурсы поддерживают CORS, можно изменить мод запроса на cors. Если запрос не выполнен, например 404 или тайм-аут, то возвращаем ответ прямо на главную страницу для обработки, в противном случае загрузка проходит успешно, клонируем ответ и помещаем его в кеш, а затем возвращаем ответ в поток главной страницы. Обратите внимание, что ресурсы, которые могут быть помещены в кеш, как правило, только GET, а те, которые получены через POST, не могут быть закешированы, поэтому делайте выводы (конечно, вы также можете вручную изменить метод получения объекта запроса), а некоторые отдельные лица не хотят, чтобы кэшированные ресурсы также оценивались.
Таким образом, как только пользователь открывает страницу один раз, устанавливается Service Worker, и когда он обновляет страницу или открывает вторую страницу, он может кэшировать запрошенные ресурсы один за другим, включая изображения, CSS, JS и т. д. пока он есть в кеше.Независимо от того, находится ли пользователь в сети или в автономном режиме, к нему можно получить доступ в обычном режиме. Поэтому у нас, естественно, возникает вопрос, насколько велика эта кэш-память? В прошлой статье мы упомянули, что Manifest также является локальным хранилищем. Chrome на стороне ПК занимает 5 МБ. На самом деле это утверждение неверно в новой версии Chrome. В версии Chrome 61 вы можете увидеть пространство и использование локального хранилища:
Среди них Cache Storage относится к размеру пространства, занимаемого Service Worker и Manifest.Как видно из приведенного выше рисунка, общий размер пространства составляет 20 ГБ, что практически не ограничено, поэтому в основном не нужно беспокоиться о недостаточном кеш.
(4) кеш HTML
Вышеприведенный шаг (3) кэширует картинки, js и css, но если html страницы также кэшируется, например, домашняя страница, будет досадная проблема - сервис-воркер прописан на странице, но теперь при выборке страницы она берется из кэша, который каждый раз один и тот же, поэтому сервис-воркер не может обновляться, например sw-5.js, но PWA требует от нас кэширования html страницы. тогда что нам делать? В документации для разработчиков Google только упоминается, что эта проблема существует, но не объясняется, как ее исправить. Решение этой проблемы требует, чтобы у нас был механизм, чтобы знать, что html обновлен, чтобы заменить html в кеше.
Механизм обновления кеша манифеста заключается в том, чтобы увидеть, изменилось ли текстовое содержимое манифеста. Если оно изменилось, он обновит кеш. Service Worker также основан на том, изменилось ли текстовое содержимое sw.js. можно почерпнуть из этой идеи.Если после запроса html и извлечения его из кеша отправить еще один запрос на получение файла посмотреть не изменилось ли время обновления html. Поэтому кэш клиента можно обновлять, управляя этим файлом на стороне сервера. Следующий код:
this.addEventListener("fetch", function(event) {
event.respondWith(
caches.match(event.request).then(response => {
// cache hit
if (response) {
//如果取的是html,则看发个请求看html是否更新了
if (response.headers.get("Content-Type").indexOf("text/html") >= 0) {
console.log("update html");
let url = new URL(event.request.url);
util.updateHtmlPage(url, event.request.clone(), event.clientId);
}
return response;
}
return util.fetchPut(event.request.clone());
})
);
});
В зависимости от того является ли content-type заголовка ответа text/html, если да, отправьте запрос на получение файла, и решите, удалять ли кеш в соответствии с содержимым файла.Реализована обновленная функция util.updateHtmlPage следующим образом:
let pageUpdateTime = {
};
let util = {
updateHtmlPage: function (url, htmlRequest) {
let pageName = util.getPageName(url);
let jsonRequest = new Request("/html/service-worker/cache-json/" + pageName + ".sw.json");
fetch(jsonRequest).then(response => {
response.json().then(content => {
if (pageUpdateTime[pageName] !== content.updateTime) {
console.log("update page html");
// 如果有更新则重新获取html
util.fetchPut(htmlRequest);
pageUpdateTime[pageName] = content.updateTime;
}
});
});
},
delCache: function (url) {
caches.open(CACHE_NAME).then(cache => {
console.log("delete cache " + url);
cache.delete(url, {ignoreVary: true});
});
}
};
Код сначала получает файл json, страница будет соответствовать файлу json, содержимое этого json следующее:
{"updateTime":"10/2/2017, 3:23:57 PM","resources": {img: [], css: []}}
В основном есть поле updateTime.Если в локальной памяти нет данных updateTime этой страницы или отличается от последнего updateTime, перевыгружайте html и кладите в кеш. Затем вам нужно уведомить поток страницы, что данные изменились, вы обновляете страницу. Это вступит в силу, не дожидаясь, пока пользователь обновит страницу. Поэтому, когда страница обновляется, используйте postMessage, чтобы уведомить страницу:
let util = {
postMessage: async function (msg) {
const allClients = await clients.matchAll();
allClients.forEach(client => client.postMessage(msg));
}
};
util.fetchPut(htmlRequest, false, function() {
util.postMessage({type: 1, desc: "html found updated", url: url.href});
});
И указать тип: 1, чтобы указать, что это сообщение для обновления html, а затем прослушать событие сообщения на странице:
if("serviceWorker" in navigator) {
navigator.serviceWorker.addEventListener("message", function(event) {
let msg = event.data;
if (msg.type === 1 && window.location.href === msg.url) {
console.log("recv from service worker", event.data);
window.location.reload();
}
});
}
Затем мы обновляем файл json, когда нам нужно обновить html, чтобы пользователь мог видеть последнюю страницу. Либо когда пользователь перезапустит браузер, оперативная память Service Worker будет опустошена, то есть переменная, хранящая время обновления страницы, будет опустошена, а страница будет перезапрошена в это время.
Следует отметить, что время HTTP-кэширования этого json-файла должно быть установлено равным 0, чтобы браузер не кэшировал его.Конфигурация nginx выглядит следующим образом:
location ~* .sw.json$ {
expires 0;
}
Поскольку этот файл должен быть получен в режиме реального времени и не может быть закэширован, firefox будет кэшировать его по умолчанию, а Chrome — нет.Кроме того, время кэширования http равно 0, и firefox не будет его кэшировать.
Существует еще один тип обновления, который обновляется пользователем. Например, пользователь оставил комментарий, и сервисному работнику необходимо уведомить об этом на странице, чтобы он удалил html-кэш и получил его снова. Это уведомление об обратном сообщении:
if ("serviceWorker" in navigator) {
document.querySelector(".comment-form").addEventListener("submit", function() {
navigator.serviceWorker.controller.postMessage({
type: 1,
desc: "remove html cache",
url: window.location.href}
);
}
});
}
Service Worker также прослушивает события сообщений:
const messageProcess = {
// 删除html index
1: function (url) {
util.delCache(url);
}
};
let util = {
delCache: function (url) {
caches.open(CACHE_NAME).then(cache => {
console.log("delete cache " + url);
cache.delete(url, {ignoreVary: true});
});
}
};
this.addEventListener("message", function(event) {
let msg = event.data;
console.log(msg);
if (typeof messageProcess[msg.type] === "function") {
messageProcess[msg.type](msg.url);
}
});
Различные callback-функции вызываются в соответствии с разными типами сообщений.Если это 1, кеш удаляется. После того, как пользователь закончит комментировать, страница будет обновлена, а при удалении кеша запрос будет повторен.
Это решает проблему обновления в реальном времени.
4. Связь между тремя кэшами Http/Manifest/Service Worker
Для кэширования вы можете использовать три метода: вы можете использовать Http Cache для установки времени кэширования, вы также можете использовать кэш приложений Manifest и использовать Service Worker для кэширования.Что, если вы используете все три?
Service Worker будет иметь приоритет, потому что Service Worker перехватывает запрос и обрабатывает его первым. Если он есть в библиотеке кеша, он вернется напрямую. Если нет, обычный запрос эквивалентен отсутствию Service Worker. В настоящее время ,это Манифест.Слой,если есть в кеше манифеста,то берем этот кеш,если нет,то значит манифеста нет,поэтому он будет браться из хттп кеша,если нет кеша хттп,то будет отправьте запрос на его получение. Тег Http или время изменения могут вернуть 304 Not Modified, в противном случае 200 и содержимое данных будут возвращены в обычном режиме. Вот и весь процесс приобретения.
Поэтому, если вы используете и Manifest, и Service Worker, это должно привести к тому, что один и тот же ресурс будет сохранен дважды. Однако можно заставить браузеры, поддерживающие Service Worker, использовать Service Worker, а те, которые не поддерживают, использовать Manifest.
5. Используйте манифест веб-приложения, чтобы добавить запись рабочего стола
Обратите внимание, что мы говорим о другом манифесте.Этот манифест представляет собой файл json, который используется для размещения такой информации, как имя значка веб-сайта, для добавления значка на рабочий стол и для создания эффекта, подобного открытию этой веб-страницы. приложение. Упомянутый выше манифест является манифестом упраздненного кэша приложений.
Этот файл Maifest.json можно записать так:
{
"short_name": "人人FED",
"name": "人人网FED,专注于前端技术",
"icons": [
{
"src": "/html/app-manifest/logo_48.png",
"type": "image/png",
"sizes": "48x48"
},
{
"src": "/html/app-manifest/logo_96.png",
"type": "image/png",
"sizes": "96x96"
},
{
"src": "/html/app-manifest/logo_192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/html/app-manifest/logo_512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/?launcher=true",
"display": "standalone",
"background_color": "#287fc5",
"theme_color": "#fff"
}
Для значка необходимо подготовить различные спецификации, а максимальный размер должен составлять 512 пикселей * 512 пикселей, чтобы Chrome автоматически выбирал подходящее изображение. Если вы измените отображение на автономный, открытие из сгенерированного значка будет похоже на открытие приложения без адресной строки браузера. start_url указывает ссылку входа после открытия.
Затем добавьте тег ссылки, указывающий на этот файл манифеста:
<link rel="manifest" href="/html/app-manifest/manifest.json">
В сочетании с кешем Service Worker следующим образом:
Кэшируйте страницу, на которую указывает start_url, с помощью Service Worker, чтобы, когда пользователь открывает страницу в браузере Chrome, в нижней части Chrome отображалось всплывающее окно с запросом на добавление этой страницы на рабочий стол. , и щелчок по этому значку аналогичен открытию приложения. Почувствуйте себя так:
Что еще более смущает, так это то, что Manifest в настоящее время поддерживается только Chrome и может использоваться только в системах Android.Браузеры IOS не могут добавлять значок на рабочий стол, потому что IOS не открывает этот API, а его собственный Safari может.
Таким образом, в этой статье рассказывается, как использовать Service Worker в сочетании с Manifest для создания автономного веб-приложения PWA, в основном используя Service Worker для управления кешем.Поскольку он написан на JS, он более гибкий, а также может взаимодействовать с Страница. Кроме того, запрашивается время обновления страницы. Определите, нужно ли обновлять html-кеш. Совместимость Service Worker не особенно хороша, но будущее большое, и браузеры готовятся к его поддержке. На этом этапе автономные приложения можно комбинировать с Манифестом автономного кэша.
Связанное чтение:
- Почему вы должны обновить свой сайт до HTTPS
- Как обновить сайт до http/2
- Как я заставил свой сайт использовать манифест HTML5