In diesem Artikel möchte ich über Service Workers (SW) sprechen. Mit SWs können wir unsere Anwendung für die Offline-Arbeit vorbereiten, sodass sie auch dann funktioniert, wenn wir keine Internetverbindung haben. Sie ermöglichen es uns auch, viele andere erweiterte Funktionen wie Push-Benachrichtigungen oder Hintergrundsynchronisierung zu verwenden. SW wird auch nach dem Schließen des Browsers weiter ausgeführt, was bedeutet, dass Service Worker weiterhin ausgeführt werden. Dies ist ein Hintergrundprozess. Registrieren wir also unseren ersten Servicemitarbeiter.
(In diesem Artikel werde ich SW-bezogene Funktionen in einfachem JS implementieren, da der Code in einfachem JS geschrieben ist, können wir ihn in alle JS-Frameworks wie Angular, React oder Vue integrieren.)
Fügen Sie als ersten Schritt die Datei sw.js zum Stammverzeichnis des Projekts hinzu. In app.js müssen wir prüfen, ob SW im Navigator verfügbar ist, dh ob SW von diesem Browser unterstützt wird. Nachdem wir wissen, dass die SWs verfügbar sind, können wir die Methode navigator.serviceWorker.register () ausführen und den Pfad zu der Datei angeben, in der sich unsere SW befindet, um sie zu registrieren. Diese Methode gibt tatsächlich ein Versprechen zurück. Um Informationen zu erhalten, können wir uns ihm anschließen, sobald dies erledigt ist.

if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js')
.then(event => {
console.log('Service worker registered', event);
});
}
SW, . , SW . , . SW, , , self, « SW», addEventListener (). SW , , , , Service Worker’a. , , . , Service Worker .

self.addEventListener('install', event => {
console.log('Installing [Service Worker]', event);
});
. Service Worker’a - , , . caches, API , open (), . , . event.waitUntil (). , . . then . cache.addAll () , .

self.addEventListener('install', event => {
console.log('Installing [Service Worker]', event);
event.waitUntil(
caches.open('static')
.then(cache => {
console.log('[Service Worker] Precaching App Shell');
cache.addAll([
'/',
'/index.html',
'/favicon.ico',
'/src/js/app.js',
'/src/js/chart.js',
'/src/js/materialize.js',
'/src/js/materialize.min.js',
'/src/css/materialize.css',
'/src/css/materialize.min.css',
'/src/css/style.css',
'https://fonts.googleapis.com/icon?family=Material+Icons',
'https://code.jquery.com/jquery-2.1.1.min.js',
'https://cdn.jsdelivr.net/npm/chart.js@2.8.0'
]);
}));
});
, -.

, . , . , , - . Fetch , - - , css js xhr. , fetch Service Worker’a , . , , .

self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response;
} else {
return fetch(event.request);
}
})
);
});
event.respondWith () , . Service Worker’ , , fetch. , Service Worker, . , , . cashes.match () , . , . , , , , , , . , , , , fetch (event.request). - .

, - , « » . , , , . , . , . , , , . , .

Object.keys(pureData).forEach(key => tmp[sorter[key.toLowerCase()]] = { key, value: pureData[key] });
tmp.forEach(obj => orderedData[obj.key] = obj.value);
const ctx = document.getElementById('myChart').getContext('2d');
new Chart(ctx, {
type: 'line',
data: {
labels: Object.entries(orderedData).map(([key, _]) => key),
datasets: [{
label: 'Users',
backgroundColor: '#26a69a',
borderColor: '#26a69a',
fill: false,
data: Object.entries(orderedData).map(([_, value]) => value),
}]
}
});
});
};

, , , .

self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response;
} else {
return fetch(event.request)
.then(res => {
return caches.open('dynamic')
.then(cache => {
cache.put(event.request.url, res.clone());
return res;
})
});
}
})
);
});
, , , . , caches, API open (), . cache.put () , . , , - URL- , . - . , , , , . . . . xhr. , css .

. - , . ? SW . , - , , , , indexedDB. , , SW . SW, . , , . , , Service Worker’y . , . - , , API, . Service Worker’y, ready, , . , . , ( ), . , , . , « ». Service Worker’, , , , , .

if ('serviceWorker' in navigator && 'SyncManager' in window) {
navigator.serviceWorker.ready
.then(sw => {
sw.sync.register('sync-request')
});
}
, «POST DATA» , , indexedDB . , indexedDB. , . . - . «sunday», 10 ( :)). writeData utility.js, . - , , - . .

const syncButton = document.getElementById('sync-button');
syncButton.addEventListener('click', _ => {
if ('serviceWorker' in navigator && 'SyncManager' in window) {
navigator.serviceWorker.ready
.then(sw => {
const data = {
id: new Date().getTime(),
sunday: 10
};
writeData('sync-requests', data)
.then(_ => {
sw.sync.register('sync-request')
});
});
}
});
, , - . , , .

self.addEventListener('sync', event => {
console.log('[Service Worker] Syncing');
if (event.tag === 'sync-request') {
event.waitUntil(
readAllData('sync-requests')
.then(async data => {
const requests = [];
for (const d of data) {
requests.push(fetch('https://simple-pwa-8a005.firebaseio.com/data.json', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
sunday: d.sunday
})
}));
}
const results = await Promise.all(requests);
results.map((response, index) => {
if (response.ok) {
deleteItemFromData('sync-requests', data[index].id);
}
})
})
);
}
});
. event.waitUntil (), , , . , indexedDB ( utility.js), , post , indexedDB, . . . , , «POST DATA» .

Nach dem Drücken der Schaltfläche "POST DATA" passiert nichts, wenn wir offline sind. Wenn die Verbindung wiederhergestellt ist, wird die Synchronisierung abgeschlossen.

Um zu bestätigen, dass die Daten tatsächlich an den Server gesendet wurden, müssen wir zuerst unsere Abrufanforderung aus dem dynamischen Cache entfernen und auf die Schaltfläche GET DATA klicken.

Das ist alles für jetzt. Bis später. Mein Code ist auf github verfügbar: https://github.com/Draakan/simplePWA