{"id":7432,"date":"2024-08-10T11:03:45","date_gmt":"2024-08-10T16:03:45","guid":{"rendered":"https:\/\/justinparrtech.com\/JustinParr-Tech\/?p=7432"},"modified":"2024-10-21T12:11:19","modified_gmt":"2024-10-21T17:11:19","slug":"cache-busting-using-javascript","status":"publish","type":"post","link":"https:\/\/justinparrtech.com\/JustinParr-Tech\/cache-busting-using-javascript\/","title":{"rendered":"Cache Busting using Javascript"},"content":{"rendered":"<h1>Cache Busting using Javascript<\/h1>\n<p>&nbsp;<\/p>\n<h2>Problem<\/h2>\n<p>Google Chrome (and possibly, other browsers) don&#8217;t properly honor the Cache-Control header.<\/p>\n<p>If you are on Page A, click a link for Page B, then hit the back button to go back to Page A, Chrome uses a pre-rendered, cached version of Page A, which may now have stale content.<\/p>\n<table>\n<tbody>\n<tr>\n<th>Action<\/th>\n<th>Location<\/th>\n<\/tr>\n<tr>\n<td>Start<\/td>\n<td>Page A<br \/>\n8:05 AM<\/td>\n<\/tr>\n<tr>\n<td>Click link on Page A<\/td>\n<td>Page B<br \/>\n8:10 AM<\/td>\n<\/tr>\n<tr>\n<td>Hit browser back button<\/td>\n<td>Page A<br \/>\n<strong><span style=\"color: #ff0000;\">8:05 AM<\/span><\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>At this point, Page A is basically static.\u00a0 Any dynamic content won&#8217;t be refreshed, even if it executes in Javascript.<\/p>\n<p>Disrupting this behavior is known as &#8220;cache busting&#8221;.<\/p>\n<p>&nbsp;<\/p>\n<h2>Solution<\/h2>\n<p>Add this Javascript to your page&#8217;s &lt;HEAD&gt; section:<\/p>\n<pre>&lt;SCRIPT&gt;\r\nfunction nocache(){\r\n  var tc3=new Date();\r\n  var delta=tc3-tc1;\r\n  if (delta&gt;2000) {\r\n    window.location.reload();\r\n  } else {\r\n    tc1=tc3;\r\n  }\r\n}\r\nvar tc1=new Date();\r\nsetInterval(nocache,1000);\r\n&lt;\/SCRIPT&gt;<\/pre>\n<p>&nbsp;<\/p>\n<h3>How it Works<\/h3>\n<p>When the page first executes, it creates a Javascript variable tc1 with a current timestamp.<\/p>\n<p>Then, it sets up a timer callback function, nocache(), which executes every 1 second.<\/p>\n<p>When nocache executes, it creates a new timestamp (tc3), and if the difference between the two is greater than 2 seconds, it reloads the current page.\u00a0 If not, it updates the tc1 timestamp to current.<\/p>\n<p>The result is that if the page remains static for more than 2 seconds, it will refresh.\u00a0 However, as long as the page is active, it keeps updating the timestamp in tc1 instead.<\/p>\n<p>If you click the link to Page B, wait 2 or more seconds, then hit the browser&#8217;s back button, the timestamp in tc1 will be the point in time from when the link was clicked (more than 2 seconds ago).\u00a0 One second after you hit the back button, the nocache function sees that tc1 is more than 2 seconds out of date and reloads the page.\u00a0 If the page successfully reloads, tc1 is updated in the process.\u00a0 If not, it simply retries the reload every 1 second.<\/p>\n<p>Also, if your page uses JSON or XML to dynamically render content, the nocache timer function can simply call your page&#8217;s update function rather than reload the entire page.<\/p>\n<p>&nbsp;<\/p>\n<h2>Conclusion<\/h2>\n<p>When you hit the browser&#8217;s back button, Chrome tries very hard to use a pre-rendered page from cache rather than use the Cache-Control header or contact the server to see if the page is stale (which it should be doing).\u00a0 This means that when you hit the back button, any dynamic code has already executed, and the page picks up where it left off from a script execution standpoint.\u00a0 Unfortunately, this includes any events that have fired, which means that the pre-rendered version of the page is basically static.<\/p>\n<p>I have seen other solutions that use the onpageshow event, or other event hooks.\u00a0 However, I have found these to be unreliable in Chrome for cache busting.\u00a0 In contrast, the timer hook <strong>must<\/strong> be honored for basic page functionality, and therefore can&#8217;t simply be killed off like other events.<\/p>\n<p>A side effect of this approach is that if the server is unavailable and the page tries to refresh, it will get stuck in a refresh loop until the server is available again.\u00a0 This is not necessarily a negative behavior, but could easily be fine tuned using a counter, for example, to only try to refresh a set number of times and then stop.\u00a0 During page load, &#8220;retries&#8221; is set to some number, n.\u00a0 &#8220;Retries &gt; 0&#8221; is then added as a condition to the if block, which then decrements retries during each execution.\u00a0 If retries hits zero, it updates tc1 to current, which stops all attempts.\u00a0 In another variation, retries can be its own, outer &#8220;if&#8221; block, so that some other exit action can be executed, for example, alerting the user that the server is offline and the page is stale.<\/p>\n<p>A fleshed-out version would look like this:<\/p>\n<pre>&lt;SCRIPT&gt;\r\n  function nocache() {\r\n    var tc3=new Date();\r\n    var delta=tc3-tc1;\r\n<span style=\"color: #00ffff;\">    if (retries&gt;0) {\r\n<\/span><span style=\"color: #99cc00;\">      \/\/ Normal action<\/span>\r\n      if (delta&gt;2000) {\r\n<span style=\"color: #00ffff;\">        retries-=1;<\/span> \r\n        window.location.reload();\r\n      } else { \r\n        tc1=tc3; \r\n      }\r\n<span style=\"color: #0000ff;\"><span style=\"color: #00ffff;\">    } else {<\/span>\r\n<span style=\"color: #99cc00;\">      \/\/ When retries hits zero, set error text, make the element visible, and disable the nocache timer\r\n<\/span><span style=\"color: #00ffff;\">      var e=document.getElementById(\"ErrorText\");<\/span><\/span><span style=\"color: #00ffff;\">\r\n      e.innerHTML=\"<span style=\"color: #ff0000;\">The server is offline and this page is dead.  Have a nice day.<\/span>\";\r\n      e.style.visibility=\"visible\";\r\n      clearInterval(nocachetimer);\r\n    }<\/span>\r\n  } \r\n  var tc1=new Date();\r\n<span style=\"color: #00ffff;\">  var retries=3;\r\n  var nocachetimer=<\/span>setInterval(nocache,1000); \r\n&lt;\/SCRIPT&gt;\r\n<span style=\"color: #00ffff;\">&lt;DIV ID=ErrorText STYLE='visibility:hidden; display:block;'&gt;<span style=\"color: #ff0000;\">&amp;nbsp;<\/span>&lt;\/DIV&gt;<\/span><\/pre>\n<p>I hope you find this useful, and thanks for reading!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Cache Busting using Javascript &nbsp; Problem Google Chrome (and possibly, other browsers) don&#8217;t properly honor the Cache-Control header. If you are on Page A, click a link for Page B, then hit the back button to go back to Page A, Chrome uses a pre-rendered, cached version of Page A, which may now have stale [&hellip;]<\/p>\n","protected":false},"author":16,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"aside","meta":{"footnotes":""},"categories":[2],"tags":[27,28,29],"class_list":["post-7432","post","type-post","status-publish","format-aside","hentry","category-tech-support","tag-cache-busting","tag-cachebusting","tag-javascript","post_format-post-format-aside"],"_links":{"self":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7432","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/comments?post=7432"}],"version-history":[{"count":10,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7432\/revisions"}],"predecessor-version":[{"id":7451,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/posts\/7432\/revisions\/7451"}],"wp:attachment":[{"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/media?parent=7432"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/categories?post=7432"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/justinparrtech.com\/JustinParr-Tech\/wp-json\/wp\/v2\/tags?post=7432"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}