Fantastic States and Where to Find Them
Webpage states store variables, configs and other data related items for a website. Those states will determine how page is displayed, which components are active, which ones are hidden or disabled, what colour they have, and other limitless possibilities of presentation in the page.
States can also store security tokens and other sensitive data to certain degree. For example, cookies made by server, can be stored in the browser, and sent back to the server for validations. We also store OAuth token in states and sent over as header in the request.
What we will discuss in this article is how we can manage media for states and discussing pros-cons and use cases of each.
TL;DR
Volatile: gone upon reload
- Local variables
- Global Variables
Persistent: stays on reload
- Cookie: small token or hash value
- Secure and HTTP Only Cookie: session data, sensitive user data
- Server Session
- Web Storage
- IndexedDB
- Cache Storage
- URL
Local Variables
You can declare it in function, object, or class scope.
Basically, you store and use it within the scope and it will diminish once we exit the scope or the object get destroyed.
Examples:
This is the simplest place to put variable, and intended to be used locally (hence the group name implies). When the variable is needed globally, we will need it to be put in global (window) scope.
Use case for local variable is for temporary or private data.
Global Variables
Simply saying window.varA = 5 , will have varA accessible across all components in the page. An id of an element in web page, is also a global variable:
<div id=”abc”>text</div>
It can be accessed with window.abc .
It’s very easy to implement, and maybe enough for small-scale system with only few people working on it. Data can be accessed and declared easily and available right away throughout the page.
However, managing global variables like that will have a lot of scalability problem, from naming management to how we can support modularity across various teams and sub-systems.
We have to explicitly define what prefix of what object will be limited to which team. For example, window.TEAM_A_VARS will only be used by Team A, but actually in reality, other teams can alter the data without Team A knowing, and will be getting harder to trace back the changes later on in the future.
Declaring something global needs validation to avoid duplication of naming, hence we will require thorough inspection of all global variable declared in the system and sub modules. In some bad working habit, some people tend to declare variable just as global without any reason.
Use case for global variable is for globally referred component, global constants / keys, tracker ids, and other public data.
Cookie
This is probably the most common storage for web page states. It offers benefit of always synchronised state between client (web browser) and server, since all data in Cookie will be sent over in each web request, thus the server will be able to read it right away.
In the early stages of HTTP 2.0, Cookie had its golden age with storing encoded large page state into it, from user credentials, temporary form data, user menus, personalisation, to wizard pages data that can grow to several hundreds of KBs.
On the other side, we find that large size of Cookie will affect performance and reduce response time. Because of its ease of use, people abused it to the point that it clogged the system. Large data will take longer time to be submitted to server and it will also take more CPU time and memory allocation to decode Cookie data.
Because of that, Cookie is intended to store small amount of data, probably just a key or a simple hash value for session or token. We should not store form fields and other large data in cookie, since it will affect performance.
Secure & HTTPOnly Cookie
It is Cookie but with “secure” flag.(https://en.wikipedia.org/wiki/Secure_cookie)
This restrict the Cookie to be sent only in secure network (HTTPS), although if the browser didn’t comply to it, the secure flag will just be ignored.
HTTPOnly Cookie is intended for data that will be created by server, and only read by server. Usually it’s used for session, either authentication or tracking. This flag is useful to store user session and prevent it from being read by malicious JS code.
Server Session
Instead of storing the data in the browser, we can also store it in the server. This method is useful if your webpage is server side rendered (SSR). If not, there should be a mechanism to retrieve the variables, maybe through API.
Storing data in the server will still involve Cookie as session id storage.
Using server session will require continuous memory allocation in the server, thus memory requirement will be increasing linearly with number of connected user. In terms of scalability, storing large data in server session is not a preferable method.
Usage example for server session is for storing data caching and system configuration. It can be also used to store personalization data for user.
Web Storage
Introduction to HTML5 brought us Web Storage. As the name implies, it is a storage for the web, placed in the client (browser). The purpose of this storage is to accommodate larger data for a website to use.
For example, we can store web-based game progress and assets. Next time the game loads, all the assets are readily available, and we can continue playing rather than starting from beginning again.
Another usage is to store response from server API, that is most likely unchanged. We can also store lots and lots of flags, without limit.
Different from Cookie, web storage will not be sent to the server, so no matter how big we store data here, it will not affect web performance.
There are two types of web storage: session and local. Session storage persist within a browser tab. If the tab is closed, all the data will be gone. Meanwhile, local storage persist throughout the browser application. It will never be gone, and can be accessed across tabs, within the same domain.
However, web storage has some problem with data retention. There is no API in web storage to automatically delete data after certain amount of time. Along the way, data kept piled up and piled up and at certain moment, no one knows which data belongs to which.
IndexDB
It is an advanced version of Web Storage, replacing WebSQL. IndexDB is a structured version of Web Storage. Instead of just key-value pair, IndexDB is a lite version database but in the web browser. We can store data and do query at it.
It’s a better alternative to Web Storage, with capabilities also to create database and tables, so we can manage better our data and may provide offline mode when the network is not available.
Cache Storage
With the introduction of Service Worker and PWA, web browser has the capability to behave like a native application. User can install the “web page” as an icon in the desktop.
During installation, browser will download pre-cached scripts and required assets to run it locally, even in offline mode. When the icon app is clicked, a webview (browser) without any address field will pop up and provide native-like app experience.
Example usage of this cache storage is for storing:
- assets (js, css, images)
- AJAX responses
- user configurations and other cache-able data
URL
Last but not least, the URL.
It is actually most forgotten way of storing a variable, because of technical limitation of the past, yet also because of there is usually no “page reload” case in the flow.
We usually store the state in URL in the form of permalink (permanent link) to a page in the site. For example, if we want to access a post in a news site, we can go with this flow:
Open homepage (http://news.abc) -> click first news -> news displayed in the page
Usually, upon clicking the first news, it will reload the page and redirect it to a new url with id of the post attached to the url:
Attaching the id in the url as postId, is a way of storing a variable. From the url, we can induce that 1234 is the data id we are looking for.
We can store the postId in the example, but how about showing a modal. We can put a flag in the url using # (hashtag):
http://news.abc?postId=1234#showSubcribeModal
We can have flag from the #showSubscribeModal, when it’s there, a modal will be shown.
What I mentioned about technology limitation before, it is because when we modify the url query, we will need the page do to page reload, not an acceptable solution. That’s why a hashtag is used. But it just adds ambiguity whether it’s actually a data in the page or is it a bookmark of an element.
Nowadays browser, support history pushstate, where we can change url without reloading it. We can store as many flags as we need there, and upon reload, the intended behaviour will be kept just like before we were reloading it.
This method ensure consistent behaviour throughout a page, and requiring no global variable declaration inside the code, because it can be read by any component of the page using window.location.href API.
Use cases of url states are usually for modal page, wizard, sub page, resource id, paging data, and many more.
We Are Hiring for Blibli.com Bandung and Jakarta
Interested on tweaking web and worked with the cutting edge technology? Come and join us Blibli.com Frontend Engineers. We are also opening office in Bandung.
You can contact me directly Hidayat Febiansyah through email hidayat.febiansyah@gdn-commerce.com
Conclusions
There may be many other ways to store web states, other alternatives are welcome in comment section.
We may soon see how native apps get replaced by their web-based substitutes, with less compatibility headache yet providing easier development and delivery.