We'll talk about ways you can effectively cache requests sent to backend without fidelling with backend HTTP headers.
Coordinating data between state changes can be hard, consider an application where you are sending request to the backend to get a list of posts to be displayed, and when user clicks on a post the application sends another request to get that post data. Now the backend is fairly simple so you get the precise data for that post, but you also want to display the title of next post and previous post, and maybe some sponsor data which is shared during the user's session. Requesting data again from backend is wasteful in such cases so the frontend has some options at this point.
Managing Javascript state
The frontend can keep a track of the data that will be reused. Storing that data in a global variable, passing state to higher levels, or using an api like React Context. There are problems with each of these approaches, global variables are evil by default. Passing data around components or maintaining it in a context like api can become messy as number of requests grow.
Using a state management framework
This is a very typical use case for a JavaScript state management framework like redux. They provide a way to manage complex application data. But if you are anything like me, the idea of introducing a new framework and overhead of learning to code around it can be a daunting task. These frameworks can also force opinionated design on your frontend so for someone who is not familiar with one, it can be a big commitment.
Browser Storage (the real MVP)
We come at our final answer, browser storage api. It is a key value store which is managed by the browser. There are two types of browser storages: local and session. Both of these provide a similar api, but, while the local storage is never cleared, session storage is cleared after the tab is closed. This approach is a lot better than our previous approaches as it's not as barebones as passing the state around and not as complex as learning a new state management framework.
Browser storage api includes only two operations, setItem
and getItem
and as you can probably guess setItem
stores the value for a given key and getItem
retrieves the value. We are free from managing the state ourselves and can just provide the key and value for the data to store and retrieve it later.
An example use of this api is demonstrated by creating a function that invokes a GET request to a url and returns the result as a promise.
// Without caching
function FetchData(url) {
return fetch(url).then(res => res.text())
}
// With Caching
function FetchData(url) {
let storageData = sessionStorage.getItem(url);
if (storageData === null) {
return fetch(url).then(res => res.text()).then(textData => {
sessionStorage.setItem(url, textData)
return textData
})
}
return Promise.resolve(storageData);
}
We treat the provided url as our key and store the fetched data, so that any subsequent request is fulfilled from the cache. The best part about this approach is that it is easier to understand and doesn't intrude with our frontend code. It is also the best solution for our problem in this case.
Caching is one of the most effective techniques to optimize performance and user experience. Storing request data on the frontend provides speedy navigation and greater control over what is stored by avoiding unnecessary requests to the backend.
If you like my posts checkout my blog
Top comments (4)
LocalStorage and SessionStorage both are synchronous operations and will block browser on large datasets, you must consider
IndexedDb
over it, and there are shims available with deprecated browserSql
.Thanks for the comment, I did look into it, but I think that it has a bit more complex api. Also Indexed db is aimed at more complex operations like traditional databases whereas session storage is a bit simpler and can handle cache invalidation with session storage.
I am not saying that it cannot be replaced, Indexed db is still a lot better option than managing state itself, and if blocking the main thread becomes a performance bottleneck then it might be worthwhile to look into it.
Cool article! I'm curious to how cache invalidation works though?
Currently only session storage has automatic data clearance where data is removed if a user closes the tab.
If you are using state management framework or passing data around a single page app then as soon as you navigate away from that page your data will be cleared. Both localstorage and indexed db store data for as long as possible.