In the current state of the web, performance plays a quintessential role in a user’s experience. Having a fast and fluid web application has a direct effect on the success of a website’s conversions and traffic.

After all, good performance is all about maintaining users, so keeping them engaged will only lead to positive results in any business venture.

When loading a webpage, JavaScript can be one of the heavier assets requested by a website. After being retrieved from the server once, in order to be performant, the user’s browser should ideally not have to request the same JavaScript bundle again.

This is where the process of caching yields benefits if the user’s browser has access to an asset that was already retrieved, they are going to have a quicker experience as a result.

So, if we want a user not to retrieve any asset repeatedly, does JavaScript get cached?

In general, most modern browsers will cache JavaScript files. This is standard practice for modern browsers and ensures an optimized loading experience.

This cached asset (JavaScript) will typically be served from the browser instead of making a request if navigating to a URL that has previously been visited. 

Since JavaScript provides the foundation of a user interacting with a webpage, serving the cached version results in a quicker time for a user to start this interaction.

Google Chrome and most modern browsers provide a run-time environment for their JavaScript called the V8 engine. There are, of course, optimizations that can be made by a developer to get the most out of caching.

However, a more passive approach might be more effective here as even though changes can be made to improve caching, the logistics behind browsers caching process is subject to change in its version updates.

This can result in creating caching improvements that are no longer valid after a few months, essentially nullifying the work that went into it.   

So, while JavaScript can be optimized for browser caching, the actual type of caching is decided by configurations in an HTTP request.

Let’s explore this further.

What is the function of the cache in HTTP?

HTTP requesst plays a big role in determining whether a JavaScript asset is cached or not.

The goal of caching in HTTP is to reduce the need to send requests and responses. Reducing both of these will result in fewer network round-trips as well as reduced network bandwidth requirements 

With JavaScript being the most common asset requested in order to create user interaction, the reduction of these network round trips bodes well for the user’s experience.

To control how the browser caches JavaScript (and other assets) HTTP requests and responses can be configured with various directives.

Cache-Control max-age

This setting instructs the browser how long it should keep cached data after the initial retrieval.

Typically this is defined in seconds like so:

Cache-Control: max-age=<seconds>

When specifying a custom amount of seconds in this header, we must be wary of potential updates to those files.

For example, this applies if there was an update to a JavaScript file during the time where the browser continued to use the cached version.

This can cause the user to be interacting with an earlier version of the website.

This is a frequently encountered scenario in tech companies, where the developers push a change to the product and the business side is unable to see the updates.

This results in some confusion between both areas of the company but is easily remedied by clearing the cache of the browser. 

And while this situation might seem trivial, I have experienced it many times in different jobs especially during times of urgency and feature crunch. It can cause a small amount of temporary friction between business and development teams.

So these custom headers enable quite a lot of flexibility when it comes to configuring browser cache.

No cache

The no-cache directive indicates to the browser that cached versions of the requested resource can not be utilized without checking to see if there has been an updated version released since the initial caching occurred.

Typically, this check is done by using an additional header called an ETag. This is a unique token that helps to differentiate versions of the same resource.

The token will change on the server whenever the resource is updated. If the ETag in the browser is identical to the server then the cached version will be served to the user.

If these tokens don’t match, a fresh version of the resource (including JavaScript files) are downloaded. This process enables the user to get the most to date version of the assets they are requesting.

No store

The header no-store acts in a more simplified manner when compared to no-cache. It essentially disallows browsers from storing any versions of a returned responses.

In the case of retrieving heavy JavaScript files, this can cause the user’s experience of interaction to be notably slow.

The process of downloading the assets every time is undoubtedly inefficient. However this is not without good reason, the use of no-store can help to disallow the storing of personal data/private information.

Some other request options include:

Cache-Control: max-age=<seconds> Cache-Control: max-stale[=<seconds>] Cache-Control: min-fresh=<seconds> Cache-Control: no-cache Cache-Control: no-store Cache-Control: no-transform Cache-Control: only-if-cached

Some other response options include:

Cache-Control: must-revalidate Cache-Control: no-cache Cache-Control: no-store Cache-Control: no-transform Cache-Control: public Cache-Control: private Cache-Control: proxy-revalidate Cache-Control: max-age=<seconds> Cache-Control: s-maxage=<seconds>

The full list of cache headers and their functionality can be found at the MDN docs.

What is Memoization in JavaScript?

You might wonder if JavaScript has any internally caching capabilities. I mean surely such an acclaimed programming language has some sort of caching built into it?

Well, Memoization in JavaScript is a specific form of caching that allows the caching of return values of functions based on its parameters.

More precisely, for every input, the first time a function is called, JavaScript will allow it to compute the result

However, this result can be stored in memory and the next time the same function is called, the already computed data is returned.

Essentially, it’s caching for functions.

This technique is only effective when the function is expected to return the same result. This is also called a pure function.

No other factors are taken into consideration including:

  • Creates a references to a function as an input
  • Create a cache to hold the result of previous function calls
  • Future invocations of that  function will return the cached results#
  • If no cached value exists, will call the function and store the returned result in cache

If the function is relying on any of these factors, it should be noted that memoization can alter these results.

Here is one the most clear and concise demonstration of memoization of JavaScript that I’ve found:

If there is memory available to be used for memoization, then it can be worth implementing in order to eliminate some code execution. It may not worth the extra effort is programs where memory is already sparse.

It’s certainly one of the more interesting aspects of caching in JavaScript. You can spend a significant amount of time trying to optimise your code for caching, however, techniques such as memoization encourage you to reevaluate your code in order to determine if the time put in as well as the extra memory used is worth the effort.

While it is unlikely that you will use memoization wherever possible in your codebase, there are plenty of 3rd party libraries that will do a much better job for us.

Take, for example, Reselect, which provides redux selector utilities that are not recomputed unless one of its arguments changes.

This is very handy in a Redux based application, as these selectors are constantly used to call upon subsections of data in the applications state.

Having these selectors of state already computed provides efficiency for more performant web applications. 

So, if you don’t want to use 3rd party libaries and you are optimizing your functions just ensure that the functions to be memoized are pure functions.

How long does a website stay cached?

So we’ve already covered the various benefits of caching JavaScript files. Browsers provide us with a very useful utility of persisting our data in its cache.

But, surely it can’t store endless amounts of cached data, right?

How long does a website stay cached?

Well, this very much depends on the browser, settings, and configuration of the HTTP requests and responses.

Typically, browsers reserve a finite amount of disk space to complete a task. If a user stops using the browser completely, the cache can persist indefinitely.

However, if the browser is used occasionally by the user, the stored data will last until the expiration date that was set either by the internal policy of the browser or the configuration of the HTTP headers.

If the user is very active using the browser, the length of time that the cache is stored can be extended to 10 minutes or less.

There is also a minimum size for caches of small JavaScript and other code files. Chrome enforces a minimum size of 1Kib of source code files before it will cache the asset.

The process of caching such a small file is too heavy of an operation relative to the value it provides.

Conclusion

I hope I’ve highlighted the importance of cache in JavaScript and how it provides value to the user experience. Overall, I feel like caching is very pertinent in the current state of the web as web applications are getting larger and larger.

Equally, all JavaScript frameworks used to build web applications are growing in complexity. As a result, JavaScript bundles are increasing in size. even with optimizations from modern asset bundlers like Webpack.

The majority of the logic for the user to interact is contained within these assets, so the ability to have them cached will allow the user to interact much faster on subsequent visits to the same page.