IndexedDB
,
service workers, and the Background Sync API, you can build an
offline-friendly image upload system that queues uploads and retries
them automatically — so your users can upload stress-free, even when
offline.So, you’re filling out an online form, and it asks you to upload a file. You click the input, select a file from your desktop, and are good to go. But something happens. The network drops, the file disappears, and you’re stuck having to re-upload the file. Poor network connectivity can lead you to spend an unreasonable amount of time trying to upload files successfully.
What ruins the user experience stems from having to constantly check network stability and retry the upload several times. While we may not be able to do much about network connectivity, as developers, we can always do something to ease the pain that comes with this problem.
One of the ways we can solve this problem is by tweaking image upload systems in a way that enables users to upload images offline — eliminating the need for a reliable network connection, and then having the system retry the upload process when the network becomes stable, without the user intervening.
This article is going to focus on explaining how to build an offline-friendly image upload system using PWA (progressive web application) technologies such as IndexedDB
,
service workers, and the Background Sync API. We will also briefly
cover tips for improving the user experience for this system.
Planning The Offline Image Upload System
Here’s a flow chart for an offline-friendly image upload system.

As shown in the flow chart, the process unfolds as follows:
- The user selects an image.
The process begins by letting the user select their image. - The image is stored locally in
IndexedDB
.
Next, the system checks for network connectivity. If network connectivity is available, the system uploads the image directly, avoiding unnecessary local storage usage. However, if the network is not available, the image will be stored inIndexedDB
. - The service worker detects when the network is restored.
With the image stored inIndexedDB
, the system waits to detect when the network connection is restored to continue with the next step. - The background sync processes pending uploads.
The moment the connection is restored, the system will try to upload the image again. - The file is successfully uploaded.
The moment the image is uploaded, the system will remove the local copy stored inIndexedDB
.Implementing The System
The first step in the system implementation is allowing the user to select their images. There are different ways you can achieve this:
- You can use a simple
<input type="file">
element; - A drag-and-drop interface.
I
would advise that you use both. Some users prefer to use the
drag-and-drop interface, while others think the only way to upload
images is through the <input type="file">
element.
Having both options will help improve the user experience. You can also
consider allowing users to paste images directly in the browser using
the Clipboard API.
Registering The Service Worker
At the heart of this solution is the service worker. Our service worker is going to be responsible for retrieving the image from the IndexedDB
store, uploading it when the internet connection is restored, and clearing the IndexedDB
store when the image has been uploaded.
To use a service worker, you first have to register one:
Checking For Network Connectivity
Remember, the problem we are trying to solve is caused by unreliable network connectivity.
If this problem does not exist, there is no point in trying to solve
anything. Therefore, once the image is selected, we need to check if the
user has a reliable internet connection before registering a sync event
and storing the image in IndexedDB
.
Note: I’m only using the navigator.onLine
property here to demonstrate how the system would work. The navigator.onLine
property is unreliable,
and I would suggest you come up with a custom solution to check whether
the user is connected to the internet or not. One way you can do this
is by sending a ping request to a server endpoint you’ve created.
Registering The Sync Event
Once the network test fails, the next step is to register a sync event. The sync event needs to be registered at the point where the system fails to upload the image due to a poor internet connection.
After registering the sync event, you need to listen for it in the service worker.
The sendImages
function is going to be an asynchronous process that will retrieve the image from IndexedDB
and upload it to the server. This is what it’s going to look like:
Opening The Database
The first thing we need to do in order to store our image locally is to open an IndexedDB
store. As you can see from the code below, we are creating a global variable to store the database instance. The reason for doing this is that, subsequently, when we want to retrieve our image from IndexedDB
, we wouldn’t need to write the code to open the database again.
Storing The Image In IndexedDB
With the IndexedDB
store open, we can now store our images.
Now, you may be wondering why an easier solution likelocalStorage
wasn’t used for this purpose.
The reason for that is thatIndexedDB
operates asynchronously and doesn’t block the main JavaScript thread, whereaslocalStorage
runs synchronously and can block the JavaScript main thread if it is being used.
Here’s how you can store the image in IndexedDB
:
With the images stored and the background sync set, the system is ready to upload the image whenever the network connection is restored.
Retrieving And Uploading The Images
Once the network connection is restored, the sync event will fire, and the service worker will retrieve the image from IndexedDB
and upload it.
Deleting The IndexedDB Database
Once the image has been uploaded, the IndexedDB
store is no longer needed. Therefore, it should be deleted along with its content to free up storage.
With that, the entire process is complete!
Considerations And Limitations
While we’ve done a lot to help improve the experience by supporting offline uploads, the system is not without its limitations. I figured I would specifically call those out because it’s worth knowing where this solution might fall short of your needs.
- No Reliable Internet Connectivity Detection
JavaScript does not provide a foolproof way to detect online status. For this reason, you need to come up with a custom solution for detecting online status. - Chromium-Only Solution
The Background Sync API is currently limited to Chromium-based browsers. As such, this solution is only supported by Chromium browsers. That means you will need a more robust solution if you have the majority of your users on non-Chromium browsers. IndexedDB
Storage Policies
Browsers impose storage limitations and eviction policies forIndexedDB
. For instance, in Safari, data stored inIndexedDB
has a lifespan of seven days if the user doesn’t interact with the website. This is something you should bear in mind if you do come up with an alternative for the background sync API that supports Safari.
Enhancing The User Experience
Since the entire process happens in the background, we need a way to inform the users when images are stored, waiting to be uploaded, or have been successfully uploaded. Implementing certain UI elements for this purpose will indeed enhance the experience for the users. These UI elements may include toast notifications, upload status indicators like spinners (to show active processes), progress bars (to show state progress), network status indicators, or buttons to provide retry and cancel options.
Wrapping Up
Poor
internet connectivity can disrupt the user experience of a web
application. However, by leveraging PWA technologies such as IndexedDB
,
service workers, and the Background Sync API, developers can help
improve the reliability of web applications for their users, especially
those in areas with unreliable internet connectivity.
No comments:
Post a Comment