DEV Community

Uriel
Uriel

Posted on • Updated on

Caching AJAX requests with SessionStorage

There are some scenarios when caching the response from an AJAX request will work better than having to make the same request everytime the user refreshes the page.

Such scenarios are easy to identify when you're working with:

  • Data that does not update very often.
  • APIs with a request limit, such as the GitHub Public API
  • Lazy loading elements that do not change very often

For some cases, it would be neccessary to create a complex system to save the response of the request in the AJAX, update it, expire it, keep it up to date, etc. But, for most cases, just a simple way to save it for a period of time is all you need, enter SessionStorage.

SessionStorage is the non so popular brother of LocalStorage, the most common storage brother in the JavaScript Web APIs family. What makes SessionStorage different from LocalStorage? Well, it turns out that whatever you save into SessionStorage expires after the user closes the browser, like every other session.

Given the nature of SessionStorage, a persistent storage that expires just after the user closes the browser, it's the perfect API to save something for a short period of time, whithout having to worry about expiring the data, just save it there and await for it to expire.

Using SessionStorage

SessionStorage has the same API than LocalStorage, the only difference between the tow of them is how they expire the data, while the browser will only delete the data from LocalStorage in case it requires it, SessionStorage data will be delated when the session finishes.

For those who have never used neither LocalStorage or SessionStorage, there's two common operations that you do with them, writing and reading:

  //Saves the string Hello world with the key message
  sessionStorage.setItem("message", "Hello world"); 
  // Retrieves the string using the key
  sessionStorage.getItem("message") // Returns "Hello world"

With these two operations we can now cache the response from an AJAX request, suppose we have to retrieve our repos from GitHub:

function getMyRepos(){
  const endpoint = "https://api.github.com/users/urielhdz/repos" //Replace urielhdz with your own username

  /* get_data */
}

Now, we'lll using the native fetch operation to retrieve data from the network in order to cache it later:

function getMyRepos(){
  const endpoint = "https://api.github.com/users/urielhdz/repos" //Replace urielhdz with your own username

  fetch(endpoint).then(r => r.json()); // the json method parses the response into a JSON object
}

To make the code more readable we'll use async functions, but keep in mind that this is not a crucial part of the tutorial, it's only syntactic sugar to make the code more clean:

async function getMyRepos(){
  const endpoint = "https://api.github.com/users/urielhdz/repos" //Replace urielhdz with your own username

  const data = await fetch(endpoint).then(r => r.json()); // the json method parses the response into a JSON object
}

Now the data constant stores the data response from the GitHub API, and here it comes the interesting part, cache that response to avoid unneccesary requests to the same API.

async function getMyRepos(){
  const endpoint = "https://api.github.com/users/urielhdz/repos" //Replace urielhdz with your own username

  const key = "githubRepos"; // Key to identify our data in sessionStorage

  // First check if there's data in SessionStorage
  let data = sessionStorage.getItem(key);

  if(data){
    // If there's somethin in the sessionStorage with our key, return that data:
    return JSON.parse(data);
  }

  //If there's nothing in the storage, make the AJAX request:
  data = await fetch(endpoint).then(r => r.json());

  //Then save it into the storage to avoid more requests later on:
  sessionStorage.setItem(key, JSON.stringify(data));

  return data;  
}

Keep in mind that both LocalStorage and SessionStorage can only save strings, so in order to save a more complex structure, such as a JSON object, we have to convert it into a string, that means that when we retrieve the data, we have to parse the string into the previous JSON object.

And that's it, now we have a method that will request data from GitHub only when neccessary, the data will expire as soon as the user closes the browser and that will allow us to keep the data updated.

Drawbacks

As pointed out by Scott Simontis in the comments, this solution with SessionStorage presents some problems:

  1. SessionStorage is sync, so keep in mind that bot writing and reading data from the storage are operations that will block the main thread of your application.
  2. Data stored in SessionStorage can be manipulated by the end user, so you shouldn't store sensitive or critical data for your application.

Thanks to Scott for pointing out this problems, as I add in the comments, this solution is aimed to simple and basic problems in which other cache solutions will appear too complex.

Discussion (6)

Collapse
ssimontis profile image
Scott Simontis

A lot of developers forget that they have a nearly universal cache available to them...HTTP caching! If you use cache headers correctly, the browser does all of the work for you!

Client-side caching also forces you to consider a lot of security concerns. A user can easily access session state and modify it, compromising the integrity of saved responses and injecting untrusted data that is about to be parsed. SessionStorage is also synchronous, so the retrieval will be a blocking operation.

I would encourage you to explore service workers to handle your caching needs. IndexedDb gives you the power to store more expressive relational data and it is asynchronous to boot!

Collapse
bkimballbrian profile image
Brian Kimball

I believe you can use localforage library to asynchronously store data.

Collapse
uriel_hedz profile image
Uriel Author

Although I think that your concerns should be highlighted in the article so, what do you think if I add them as a warning, with credits to your comment?

Collapse
ssimontis profile image
Scott Simontis

Please feel free to do so! If you have any questions along the way feel free to ask.

Collapse
uriel_hedz profile image
Uriel Author • Edited

This is an alternative for simple cases in which introducing a service worker or an indexedDB database would be an overkill,

Collapse
heemoe profile image
Hee Z

It seems limited 5MB of SessionStorage