{"id":327,"date":"2020-08-22T07:30:03","date_gmt":"2020-08-22T05:30:03","guid":{"rendered":"http:\/\/www.myblog.nguenkam.com\/?p=327"},"modified":"2022-06-08T18:00:39","modified_gmt":"2022-06-08T16:00:39","slug":"how-to-combine-advantages-of-localstorage-and-sessionstorage","status":"publish","type":"post","link":"https:\/\/nguenkam.com\/blog\/index.php\/2020\/08\/22\/how-to-combine-advantages-of-localstorage-and-sessionstorage\/","title":{"rendered":"How to combine advantages of localStorage and sessionStorage"},"content":{"rendered":"\n<h4 class=\"has-vivid-red-color has-text-color\">Use-case:<\/h4>\n\n\n\n<p>let\u00b4s say , we want to share some informations (for example, an authentication token) between browser tabs which would suggest to use&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en\/docs\/Web\/API\/Window\/localStorage\">HTML5&nbsp;<code>localStorage<\/code><\/a>. But we don&#8217;t want anything related to authentication to stay in my storage when the browser is closed which would suggest using&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Window\/sessionStorage\">HTML5&nbsp;<code>sessionStorage<\/code><\/a>.<\/p>\n\n\n\n<p>The first alternative would be to use cookies , because the cookies meet all the above requirements.<\/p>\n\n\n\n<ul><li><em>Cookies are shared across all same origin tab. You can even specify their paths, but they are shared by default.<\/em><\/li><li><em>Cookies are automatically deleted by browser when it is closed, you need to do nothing; this is again the default behaviour.<\/em><\/li><li><em>Cookies can be easily made as secure or more secure than storage.<\/em><\/li><\/ul>\n\n\n\n<p> But, there is some problem with this solution.<strong>Cookies<\/strong>&nbsp;are&nbsp;<strong>sent with every request<\/strong>, so they can worsen performance (especially for mobile data connections). At that time, we will not use it yet.<\/p>\n\n\n\n<p>another option to achieve this, could be to clean the&nbsp;<code>localStorage<\/code>&nbsp;when the page is about to be closed\/unloaded, so nothing stays behind in storage. That way the&nbsp;<code>localStorage<\/code>&nbsp;would behave like the&nbsp;<code>sessionStorage<\/code>&nbsp;in the sense that it would be removed once the page is closed, but it would still have the advantage from the&nbsp;<code>localStorage<\/code>&nbsp;of sharing data across tabs.<\/p>\n\n\n\n<p>For that we could use the&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Events\/beforeunload\"><code>onbeforeunload<\/code><\/a>&nbsp;event:<\/p>\n\n\n\n<p class=\"has-text-align-center has-vivid-cyan-blue-color has-text-color\">The beforeunload event is fired when the window, the document and its resources are about to be unloaded.<\/p>\n\n\n\n<p>Something like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ when the page is about to be unloaded, remove the localStorage data\nwindow.addEventListener(\"beforeunload\", function() {\n    \/\/our method here\n});<\/code><\/pre>\n\n\n\n<p>Let\u00b4s translate it in Angular : <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@HostListener('window:beforeunload') onBeforeUnload() {\n   \/\/ our method here\n  }<\/code><\/pre>\n\n\n\n<p>One option to achieve this could be to clean the&nbsp;<code>localStorage<\/code>&nbsp;when the page is about to be closed\/unloaded, so nothing stays behind in storage. That way the&nbsp;<code>localStorage<\/code>&nbsp;would behave like the&nbsp;<code>sessionStorage<\/code>&nbsp;in the sense that it would be removed once the page is closed, but it would still have the advantage from the&nbsp;<code>localStorage<\/code>&nbsp;of sharing data across tabs.<\/p>\n\n\n\n<p>For that we could use the&nbsp;<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Events\/beforeunload\"><code>onbeforeunload<\/code><\/a>&nbsp;event:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>The beforeunload event is fired when the window, the document and its resources are about to be unloaded.<\/p><\/blockquote>\n\n\n\n<p>Something like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ code here\n...\n\n\/\/ you have the data in the localStorage\nlocalStorage.setItem(\"data\", \"My Data\");\n\n\/\/ more code here\n...\n\n\/\/ when the page is about to be unloaded, remove the localStorage data\nwindow.addEventListener(\"beforeunload\", function() {\n    localStorage.removeItem(\"data\");\n});<\/code><\/pre>\n\n\n\n<p>That is a good start for solving our issue. But that solution is way too simple, and there is a catch: when you close one tab, the&nbsp;<code>localStorage<\/code>&nbsp;data is deleted, even if you have other tabs open! (leaving them without any data). To prevent removing the data when one of the tabs is closed, you could keep track of the number of tabs, and only clean the&nbsp;<code>localStorage<\/code>&nbsp;when the number is zero.<\/p>\n\n\n\n<p>The pseudo-code for that would be:<\/p>\n\n\n\n<ol><li>On page load:<ol><li>If the&nbsp;<code>localStorage<\/code>&nbsp;has a count of tabs<ol><li>Increment the tab count by 1<\/li><\/ol><\/li><li>Or else (no count of tabs)<ol><li>Create a variable in the&nbsp;<code>localStorage<\/code>&nbsp;that will contain the number of tabs.<\/li><li>Set that variable to 1 (the current tab).<\/li><\/ol><\/li><\/ol><\/li><li>On page unload:<ol><li>Decrease the tab count by 1.<\/li><li>If the tab count is zero (this was the last tab open)<ol><li>Delete the content of the&nbsp;<code>localStorage<\/code><\/li><\/ol><\/li><\/ol><\/li><\/ol>\n\n\n\n<h4 class=\"has-vivid-red-color has-text-color\"><u>Troubleshooting<\/u><\/h4>\n\n\n\n<p>This could be a nice start solution, but we still have one painful caveat: <\/p>\n\n\n\n<p class=\"has-vivid-red-color has-text-color\"><strong><em>If the user only has one tab open and they refresh the page, the storage gets cleared.<\/em><\/strong><\/p>\n\n\n\n<p>&nbsp;We will go around that issue by copying the value of&nbsp;<code>localStorage.data<\/code>&nbsp;to&nbsp;<code>sessionStorage.data<\/code>&nbsp;right before removing it from the&nbsp;<code>localStorage<\/code>, then on load if there are no tabs, check if&nbsp;<code>sessionStorage.data<\/code>&nbsp;exists and initialize it to that value. The sessionStorage will be preserved in a refresh but not on a window\/tab close.<\/p>\n\n\n\n<h4>Final Code in Javascript.<\/h4>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;script&gt;\n            window.addEventListener(\"load\", function() {\n                if (!localStorage.tabs) {\n                    \/\/Create the tab count\n                    localStorage.setItem(\"tabs\", 1);\n                    \/\/ restore data in case of refresh, or set to initial value in case of new window\n                    localStorage.setItem(\"data\", sessionStorage.getItem(\"data\") || \"Initial\");\n                } else {\n                    \/\/Add one tab to the count\n                    localStorage.tabs++;\n                }\n            });\n\n            window.addEventListener(\"beforeunload\", function() {\n                if (parseInt(localStorage.tabs) == 1) {\n                     \/\/Last tab, so we can remove localStorage\"\n                    \/\/ but first we save the data temporarily in the sessionStorage (in case of reload)\n                    sessionStorage.setItem(\"data\", localStorage.getItem(\"data\")); \n                    localStorage.removeItem(\"tabs\");\n                    localStorage.removeItem(\"data\");\n                } else {\n                  \/\/There are more tabs open, decrease count by 1\"\n                    localStorage.tabs--;\n                }\n            });\n        &lt;\/script&gt;<\/code><\/pre>\n\n\n\n<p class=\"has-vivid-red-color has-text-color\"><em>next opened issues :  For browsers or tabs crashing, the above code doesn\u00b4t work well. As result, we will end up with uncleaned or invalid count in storage.<\/em><\/p>\n\n\n\n<p>A solution could be the use of a <u>timestamp checker<\/u> : the data would still be in the&nbsp;<code>localStorage<\/code>&nbsp;but it would be deleted on load if it has been more than x time since the last update<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Use-case: let\u00b4s say , we want to share some informations (for example, an authentication token) between browser tabs which would suggest to use&nbsp;HTML5&nbsp;localStorage. But we don&#8217;t want anything related to authentication to stay in my storage when the browser is closed which would suggest using&nbsp;HTML5&nbsp;sessionStorage. The first alternative would be to use cookies , because [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1963,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1,5,58,59],"tags":[29,55,57,56],"_links":{"self":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/327"}],"collection":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=327"}],"version-history":[{"count":8,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/327\/revisions"}],"predecessor-version":[{"id":1977,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/posts\/327\/revisions\/1977"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media\/1963"}],"wp:attachment":[{"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=327"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=327"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nguenkam.com\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=327"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}