1

I'm building a quiz. A page is displaying a question, and when the user answers, another page is displaying the answer. When the user is on the question page, I would like in advance to cache the corresponding answer page.

So when the user answers a question, the answer's page is displayed without any loading time (as it is retrieved from the service worker and it's blazing fast).

What is the best approach to achieve this?

The solution I thought about:

On the question page, insert a hidden IFrame displaying the answer's page allowing the service worker to cache all resources (html and images). I think it's too tricky and it doesn't seem to be a common solution; can't really find other people using this trick, so I thought there must be a better way?

user2923322
  • 1,072
  • 1
  • 11
  • 25

2 Answers2

0

You could either:

  1. Pre-cache all up-front with a SW (caution if many pages are involved on slower connections).
  2. Configure SW to dynamically cache after each request
  3. Add cache-control headers to HTTP response so browser automatically caches and no SW is needed.

If you configure 2 and 3, issue a fetch(url) request so it caches, then subsequent requests won't use the network.

pre-cache all

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(cacheName).then(function(cache) {
      return cache.addAll(
        [
          './question/1',
          './answer/1',
          './question/1',
          './answer/2',
          ...
        ]
      );
    })
  );
});
anthumchris
  • 8,245
  • 2
  • 28
  • 53
0

You can do this if your question and corresponding answer page routes are convention based. For example, question-1.html is answered with answer-1.html. If you follow this or a similar pattern, you can capture the incoming request for question-1.html and kick off a request for answer-1.html immediately in the background.

self.addEventListener('fetch', function(event) {

  // If url is a question url, initiate answer request and cache it
  if(event.request.url.indexOf('question-') >= 0) {

    // Generate the answer url and request by convention
    var answerUrl = event.request.url.replace('question-', 'answer-');
    var answerRequest = new Request(answerUrl);

    // Initiate the fetch request for the answer page but don't wait on the response
    fetch(answerRequest).then(function(answerResponse) {
      // Cache the answer response when you get it
      caches.open('answers').then(function(cache) {
        cache.put(answerRequest, answerResponse);
      });     
    });

    // Return the question response
    event.respondWith(fetch(event.request));

  } else if(event.request.url.indexOf('answer-') >= 0) {

    // If the request is for an answer, respond from cache
    event.respondWith(caches.open('answers').then(function(cache) {
      // Return the answer from cache (or network just in case)
      return cache.match(event.request) || fetch(event.request);
    });
  }
});

There is some refinement possible in the above code. For instance, if the user is fast enough in their answer to beat the background fetch of the answer page, they may have to wait for a network response instead of using the cache but that is unlikely.

Justin Collins
  • 320
  • 2
  • 7
  • Correct me if I'm wrong, but that will only cache the HTML page and not its associated resources such as images. – user2923322 Jan 09 '20 at 02:44
  • That's correct. If you were wanting to get images or other assets, you'll need to have a similar convention or pre-load them as suggested by @AnthumChris . – Justin Collins Jan 09 '20 at 16:06