This is a continuation of the previous blogs on adding background synchronization, you are highly encouraged to check out the previous blogs before continuing.
Getting Started
We would be required to make a request for some external resource from the web (like data fetch or post), as without that any website by default works offline. Let's create a form, whose input is submitted to a mock server.
NOTE: This is a continuation from the previous blog where the manifest & service worker have already been added.
We will only be requiring parts of the above snippet, so you may use only the required part in the corresponding file or make a separate script and add it to the service worker using importScripts() and the HTML body.
Registering Background Sync task
We need to store the data in the IndexedDB before registering the background sync task, so that the data can be accessed after the internet connection is re-established (in case the user is not connected to the web).
If the browser being used doesn't support background sync, there is no point storing it in the IndexedDB as it cannot be synced later, we directly send the request in this case.
// script.jsconstemailForm=document.querySelector('#email-form');constemailInput=document.querySelector('#email-input');IDB.initialize()emailForm.addEventListener("submit",async (e)=>{e.preventDefault()constdata={email:emailInput.value}emailInput.value=""if ('serviceWorker'innavigator&&'SyncManager'inwindow&&'indexedDB'inwindow){// storing the data in indexedDBawaitIDB.setByKey(Date.now(),data)// using current timestamp as key (not a recommended practice)// registering `background sync` taskconstregistration=awaitnavigator.serviceWorker.readyawaitregistration.sync.register('sync-emails')console.log("[DB] data stored");console.log("[FORM] sync registered");}else{// sending the request directly in case `background sync` is not supportedconstresponse=awaitfetch('https://jsonplaceholder.typicode.com/posts',{method:'POST',body:JSON.stringify(data),headers:{'Content-type':'application/json; charset=UTF-8',},})constjsonData=awaitresponse.json()console.log("[FORM] submitted (sync not supported)");console.log("[RESPONSE]",jsonData);}})
Handling the background sync in service worker
Since we stored the data in IndexedDB, we will be fetching data from the DB and sending the requests.
If the request fails (sync triggered by registering the sync task), you should throw an error to ensure its automatically registered for sync when the connection is re-established.
// sync handlerconstsyncEmails=async ()=>{constkeys=awaitIDB.getAllKeys()for (constkeyofkeys){// sending data to the serverconstdata=awaitIDB.getByKey(key)constresponse=awaitfetch('https://jsonplaceholder.typicode.com/posts',{method:'POST',body:JSON.stringify(data),headers:{'Content-type':'application/json; charset=UTF-8',},})constjsonData=awaitresponse.json()console.log("[RESPONSE]",jsonData)// removing the data from the `indexedDB` if data was sent successfullyawaitIDB.deletebyKey(key)console.log("[DB] removed",key)}}// adding sync listenerself.addEventListener('sync',function (event){console.log("[SYNC] sync event triggered");event.waitUntil(syncEmails().then(()=>console.log("[SYNC] Success")).catch((err)=>{console.log("[SYNC] Error")throwerr}));});
If you have multiple sync registrations (eg: sync-emails, sync-data, etc), you can use switch(event.tag) to handle each type of sync event.
Caveats
Some things to keep in mind:
To go offline you have to physically cut your connection to the internet (eg: turn off wifi and not use offline mode from dev tools)