2
votes

I've created a service worker enabled application that is intended to cache the response from an AJAX call so it's viewable offline. The issue I'm running into is that the service worker caches the page, but not the AJAX response the first time it's loaded.

If you visit http://ivesjames.github.io/pwa and switch to airplane mode after the SW toast it shows no API content. If you go back online and load the page and do it again it will load the API content offline on the second load.

This is what I'm using to cache the API response (Taken via the Polymer docs):

(function(global) {

  global.untappdFetchHandler = function(request) {
    // Attempt to fetch(request). This will always make a network request, and will include the
    // full request URL, including the search parameters.
    return global.fetch(request).then(function(response) {
      if (response.ok) {
        // If we got back a successful response, great!
        return global.caches.open(global.toolbox.options.cacheName).then(function(cache) {
          // First, store the response in the cache, stripping away the search parameters to
          // normalize the URL key.
          return cache.put(stripSearchParameters(request.url), response.clone()).then(function() {
            // Once that entry is written to the cache, return the response to the controlled page.
            return response;
          });
        });
      }

      // If we got back an error response, raise a new Error, which will trigger the catch().
      throw new Error('A response with an error status code was returned.');
    }).catch(function(error) {
      // This code is executed when there's either a network error or a response with an error
      // status code was returned.
      return global.caches.open(global.toolbox.options.cacheName).then(function(cache) {
        // Normalize the request URL by stripping the search parameters, and then return a
        // previously cached response as a fallback.
        return cache.match(stripSearchParameters(request.url));
      });
    });
  }
})(self);

And then I define the handler in the sw-import:

  <platinum-sw-import-script href="scripts/untappd-fetch-handler.js">

  <platinum-sw-fetch handler="untappdFetchHandler"
                     path="/v4/user/checkins/jimouk?client_id=(apikey)&client_secret=(clientsecret)"
                     origin="https://api.untappd.com">
  </platinum-sw-fetch>

    <paper-toast id="caching-complete"
                 duration="6000"
                 text="Caching complete! This app will work offline.">
    </paper-toast>

    <platinum-sw-register auto-register
                          clients-claim
                          skip-waiting
                          base-uri="bower_components/platinum-sw/bootstrap"
                          on-service-worker-installed="displayInstalledToast">
      <platinum-sw-cache default-cache-strategy="fastest"
                         cache-config-file="cache-config.json">
      </platinum-sw-cache>
    </platinum-sw-register>

Is there somewhere I'm going wrong? I'm not quite sure why it works on load #2 instead of load #1.

Any help would be appreciated.

1

1 Answers

3
votes

While the skip-waiting + clients-claim attributes should cause your service worker to take control as soon as possible, it's still an asynchronous process that might not kick in until after your AJAX request is made. If you want to guarantee that the service worker will be in control of the page, then you'd need to either delay your AJAX request until the service worker has taken control (following, e.g., this technique), or alternatively, you can use the reload-on-install attribute.

Equally important, though, make sure that your <platinum-sw-import-script> and <platinum-sw-fetch> elements are children of your <platinum-sw-register> element, or else they won't have the intended effect. This is called out in the documentation, but unfortunately it's just a silent failure at runtime.