Jamey McElveen
Jamey McElveen

Reputation: 18325

How can I use JavaScript to detect if I am on a cached page

I want to display from cache for a long time and I want a slightly different behavior on page render vs loading the page from cache. Is there an easy way I can determine this with JavaScript?

Upvotes: 28

Views: 21422

Answers (9)

Ravi Patil
Ravi Patil

Reputation: 327

You can use pageshow event. It has the read only field called persisted which will be set to true when the page is loaded from cache memory.

$(window).on("pageshow", function (event) {
    //The persisted property indicates if a webpage is loading from a cache.
    let isPersisted = event.originalEvent.persisted;

    if (isPersisted) {
       //Do the stuff.
    }
})

Upvotes: 3

Junior Tour
Junior Tour

Reputation: 638

Try performance.getEntriesByType('resource') API, it will return each stage time and its name, type of all network resource like this:

enter image description here

Above screenshot shows we got the file named https://www.google.com/xjs/_/js/k=xjs... download total duration is 925 (ms), its type is script.

So we can detect if some files hit cache based on its duration, and filter type or name we want to focus:

const includeFileTypes = [
  'script',
  // 'css',
  // 'img',
]
const includeFileNames = [
  'yourTargteFileName.js',
]

function getFileNameFromURL(url) {
  return url?.match(/[^\\/]+(?!.*\/)/)?.[0]
}

const getResourceTiming = () => {
  const resources = performance
    .getEntriesByType('resource')
    .filter(({ initiatorType }) => {
      return includeFileTypes.includes(initiatorType)
    })
    // .filter(({ name }) => {
    //   return includeFileNames.includes(getFileNameFromURL(name))
    // });
  return resources.map(
    ({
      name,
      // redirectEnd,
      // redirectStart,
      // domainLookupEnd,
      // domainLookupStart,
      // connectEnd,
      // connectStart,
      // secureConnectionStart,
      responseEnd,
      responseStart,
      // fetchStart,
      // requestStart,
      startTime,
      duration,
    }) => ({
      name: getFileNameFromURL(name),
      startTime: parseInt(startTime),
      endTime: parseInt(responseEnd - responseStart),
      duration: parseInt(duration),
    }),
  );
};

function getHitCacheFiles(allTargetResources) {
  return allTargetResources?.filter(({name, duration}) => {
    if (duration < 20) {
      console.log(`Hit Cache: ${name}`)
      return true
    } else {
      console.log(`Not Hit Cache: ${name}`)
      return false
    }
  })
}


const allTargetResources = getResourceTiming()

console.table(getHitCacheFiles(allTargetResources))

DEMO

It will print:

enter image description here

It is also align to DevTool Network panel:

enter image description here

getEntriesByType('resource') usage is simpler than transferSize, it don't need extra HTTP header Timing-Allow-Origin: https://yoursite.com

References: transferSize#cross-origin_content_size_information

Upvotes: 2

Jamey McElveen
Jamey McElveen

Reputation: 18325

I started with the answer "Daniel" gave above but I fear that over a slow connection I could run into some latency issues.

Here is the solution that ultimately worked for me. On the server side I add a cookie refCount and set it's value to 0. On document load in javascript I first check refCount and then increment it. When checking if refCount is greater than 1 I know the page is cached. So for this works like a charm.

Thanks guys for leading me to this solution.

Upvotes: 22

Afterparty
Afterparty

Reputation: 69

  1. Add unique data to the page on the server at creation. For example a random number, or the creation time:
       window.rand = {{ rand() }} 
  1. Use local storage to save the url with the number and compare it later if needed:
       reloadIfCached() {
            var cached = localStorage.getItem(window.location.href) == window.rand;
            if (cached) {
                window.location.reload();
            }
            localStorage.setItem(window.location.href, window.rand);
       }

Upvotes: 1

Knaģis
Knaģis

Reputation: 21515

With the new Resource Timing Level 2 spec you can use the transfer size property to check if the page is loaded from cache:

var isCached = performance.getEntriesByType("navigation")[0].transferSize === 0;

Upvotes: 16

Will Dieterich
Will Dieterich

Reputation: 504

Not directly, some browsers may have some custom command for it.

There is a workaround that would do what you want. Use a cookie to store timestamp of the first visit and then use the META HTTP-EQUIV to set the length of time the file is cached (cacheLength). If the current time is within the time period from timestamp to timestamp+cacheLength then treat as if they loaded from cache. Once the cache has expired reset the cookie time.

Upvotes: 1

Reactgular
Reactgular

Reputation: 54821

While this question is already 4 years old. I thought I would add my 2 cents using jQuery and the History plugin.

$(document).ready(function()
{
    $('body').append('<div class="is_cached"></div>');
});

History.Adapter.bind(window,'statechange',function(){
   if($('.is_cached').length >= 1)
   {
      alert('this page is cached');
   }
});

When the document is first loaded. A new div.is_cached is appended. There isn't a compatible way to execute javascript when loading a cached page, but you can monitor for history changes. When history changes and the div.is_cached exists, then the user is viewing a cached paged.

Upvotes: 4

Allain Lalonde
Allain Lalonde

Reputation: 93458

Using XmlHttpRequest you can pull up the current page and then examine the http headers of the response.

Best case is to just do a HEAD request and then examine the headers.

For some examples of doing this have a look at http://www.jibbering.com/2002/4/httprequest.html

Upvotes: 2

Daniel
Daniel

Reputation: 4977

One way you could do it is to include the time the page was generated in the page and then use some javascript to compare the local time to the time the page was generated. If the time is different by a threshold then the page has come from a cache. The problem with that is if the client machine has its time set incorrectly, although you could get around this by making the client include its current system time in the request to generate the page and then send that value back to the client.

Upvotes: 16

Related Questions