Максим Сальников
@webmaxru
Как правильно использовать то, что уже умеет сервис-воркер
Full-stack разработчик "приложений из будущего" в ForgeRock
Service Worker API
install, activate, fetch, backgroundfetchsuccess, backgroundfetchfail, backgroundfetchclick
sync
push, notificationclick
paymentrequest
Вебсайт
Сервис-воркер
Браузер/ОС
Event-driven воркер
'install'
Загрузка
Установка
Активация
Удален
'activate'
[Ожидание]
Активен
Эти приложения запускаются везде и обладают рядом характеристик, обеспечивающих пользователей преимуществами, аналогичными тем, что доступны в нативных решениях.
За флагом
OS
My App
Определиться с минимально необходимым набором ресурсов
Доступна новая версия.
Обновить?
Сервис-воркер
install: поместить ресурсы в Cache Storage
activate: очистить Cache от ресурсов предыдущей версии приложения
fetch: если ресурс в Cache Storage, выдать его оттуда, иначе — загрузить из сети (и закешировать)
Build time
Зарегистрировать сервис-воркер и проверять, не обновился ли он
Вебсайт
PWA Feature Detector
Web API Confluence
if ('serviceWorker' in navigator) {
// Регистрируем сервис-воркер
}
if ('SyncManager' in window) {
// Реализуем функциональность для оффлайн-режима
}
if (!('PushManager' in window)) {
// Прячем интерфейс подписки на push-уведомления
}
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw-workbox.js')
.then(...);
}
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw-workbox.js')
.then(...);
)};
}
const appShellFilesToCache = [
...
'./non-existing.html'
]
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('appshell').then((cache) => {
return cache.addAll(appShellFilesToCache)
})
)
})
if ('storage' in navigator && 'estimate' in navigator.storage) {
navigator.storage.estimate().then(({usage, quota}) => {
console.log(`Using ${usage} out of ${quota} bytes.`);
});
}
Chrome | <6% своб. пространства |
Firefox | <10% своб. пространства |
Safari | <50MB |
IE10 | <250MB |
Edge | Зависит от размера диска |
const appShellFilesToCache = [
'./styles.css',
...
'./styles.css'
]
event.waitUntil(
caches
.open('appshell').then(cache => {
return cache.addAll(['./bad-res.html'])
.catch(err => {
console.log(err)
})
})
);
event.waitUntil(
caches
.open('appshell').then(cache => {
return cache.addAll(['./bad-res.html'])
.catch(err => {
console.log(err)
throw err
})
})
);
const appShellFilesToCache = [
...
'https://workboxjs.org/offline-ga.min.svg'
]
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('appshell').then((cache) => {
return cache.addAll(appShellFilesToCache)
})
)
})
fetch(event.request).then( response => {
if (response.ok) {
let copy = response.clone();
caches.open('runtime').then( cache => {
cache.put(request, copy);
});
return response;
}
})
fetch(event.request).then( response => {
if (response.ok || response.status === 0) {
let copy = response.clone();
caches.open('runtime').then( cache => {
cache.put(request, copy);
});
return response;
}
})
navigator.serviceWorker.register('sw-handmade.js')
.then(registration => {
if (registration.waiting) {
// Показываем приглашение обновить страницу
}
})
Я прогрессивное веб-приложение, и я always fresh. Только это уже устаревшая версия. Кликни здесь чтобы обновить
workbox.core.setCacheNameDetails({precache: 'new-name'});
self.addEventListener('install', () => {
self.skipWaiting();
});
self.addEventListener('activate', () => {
self.clients.matchAll({type: 'window'}).then(tabs => {
tabs.forEach(tab => {
tab.navigate(tab.url);
});
});
});
Cache-Control: no-cache
importScripts(`/sw-lib.js?v=${VERSION}`);
navigator.serviceWorker.register('/sw.js', {
updateViaCache: 'none'
})
const swReg = await navigator.serviceWorker.register("/sw.js");
await swReg.paymentManager.instruments.set(
"My Pay's Method ID",
{
name: "My Pay's Method",
method: "https://my.pay/my-method",
}
);
self.addEventListener("paymentrequest", event => {
// Открыть окно с интерфейсом данного платежного метода
event.openWindow('https://my.pay/checkout')
});
Метод (url) задан как supportedMethods в PaymentRequest сайта продавца и в момент оплаты этот метод выбран
На HEAD-запрос по этому адресу сайт платежной системы возвращает 200 + Link:<адрес Payment Method Manifest>, где в default_applications должен присутствовать Web App Manifest метода
В Web App Manifest метода присутствует секция serviceworker с src и scope
const registration = await navigator.serviceWorker.ready;
await registration.backgroundFetch.fetch(
'my-series',
['s01e01.mpg', 's01e02.mpg'],
{
title: 'Downloading My Series',
downloadTotal: 1000000000
}
);
addEventListener('backgroundfetchsuccess', event => {
event.waitUntil(
(async function() {
try {
// Копируем результаты в Cache Storage
...
await event.updateUI({ title: `Downloaded!` });
} catch (err) {
await event.updateUI({ title: `Fail: ${err}` });
}
})()
);
});
periodicsync