Pada artikel ini, saya ingin berbicara tentang Service Workers (SW). SW memungkinkan kita untuk membuat aplikasi kita siap untuk bekerja secara offline sehingga tetap berfungsi meskipun kita tidak memiliki koneksi internet. Mereka juga memungkinkan kami untuk menggunakan banyak fitur lanjutan lainnya seperti pemberitahuan push atau sinkronisasi latar belakang. SW terus berjalan bahkan setelah browser ditutup, yang berarti Service Worker terus berjalan. Ini adalah proses latar belakang. Jadi, mari daftarkan Service Worker pertama kita.
(Pada artikel ini saya akan menerapkan fungsionalitas terkait SW di JS biasa, karena kode ditulis dalam JS biasa, kami dapat mengintegrasikan ke dalam kerangka kerja JS apa pun seperti Angular, React atau Vue)
Sebagai langkah pertama, tambahkan file sw.js ke root proyek. Di app.js, kita harus memeriksa apakah SW tersedia di navigator, yaitu jika SW didukung oleh browser ini. Sekarang kita tahu SW tersedia, kita bisa menjalankan metode navigator.serviceWorker.register (), menetapkan jalur ke file tempat SW kita berada untuk mendaftarkannya. Metode ini benar-benar mengembalikan Promise. Jadi, untuk mendapatkan informasi, setelah selesai kita bisa bergabung dengannya.
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» .
Setelah menekan tombol "POST DATA", ketika kita sedang offline, tidak ada yang terjadi, tetapi ketika koneksi dipulihkan, kita melihat bahwa sinkronisasi telah selesai.
Dan untuk memastikan bahwa data memang telah dikirim ke server, pertama-tama kita perlu menghapus permintaan pengambilan dari cache dinamis dan mengklik tombol "DAPATKAN DATA".
Itu saja untuk saat ini. Sampai jumpa lagi. Kode saya tersedia di github: https://github.com/Draakan/simplePWA