在缓存优先的Service Worker上加载后刷新页面

时间:2017-06-28 20:13:22

标签: javascript service-worker sw-toolbox

我目前正在考虑将服务工作者添加到我正在建设的网络应用中。

这个应用程序本质上是一个集合管理器。你可以CRUD各种类型的项目,它们通常紧密相连(例如A hasMany B hasMany C)。

sw-toolbox提供了一个toolbox.fastest处理程序,它进入缓存然后进入网络(在99%的情况下,缓存会更快),在后台更新缓存。我想知道的是如何通知您有可用的新版本页面。我的目的是显示缓存版本,然后,如果网络提取有更新的版本,建议用户刷新页面以查看最新的编辑。我刚才在YouTube video看到了一些东西,但主持人并不知道如何处理这个问题。

这可能吗?是否有一些事件处理程序或承诺可以绑定到请求,以便我知道何时检索到更新的版本?然后我会在页面上发布一条消息来显示通知。

如果没有,我知道我可以使用toolbox.networkFirst以及合理的超时来使网页即使在Lie-Fi上也可用,但它并不是那么好。

1 个答案:

答案 0 :(得分:0)

我偶然发现了Mozilla Service Worker Cookbooj,其中或多或少包含了我想要的东西:https://serviceworke.rs/strategy-cache-update-and-refresh.html

以下是相关部分(不是我的代码:为方便起见,请复制到此处)。

为工作人员提取方法

// On fetch, use cache but update the entry with the latest contents from the server.
self.addEventListener('fetch', function(evt) {
  console.log('The service worker is serving the asset.');
  // You can use respondWith() to answer ASAP…
  evt.respondWith(fromCache(evt.request));
  // ...and waitUntil() to prevent the worker to be killed until the cache is updated.
  evt.waitUntil(
    update(evt.request)
    // Finally, send a message to the client to inform it about the resource is up to date.
    .then(refresh)
  );
});

// Open the cache where the assets were stored and search for the requested resource. Notice that in case of no matching, the promise still resolves but it does with undefined as value.
function fromCache(request) {
  return caches.open(CACHE).then(function (cache) {
    return cache.match(request);
  });
}

// Update consists in opening the cache, performing a network request and storing the new response data.
function update(request) {
  return caches.open(CACHE).then(function (cache) {
    return fetch(request).then(function (response) {
      return cache.put(request, response.clone()).then(function () {
        return response;
      });
    });
  });
}

// Sends a message to the clients.
function refresh(response) {
  return self.clients.matchAll().then(function (clients) {
    clients.forEach(function (client) {
    // Encode which resource has been updated. By including the ETag the client can check if the content has changed.
      var message = {
        type: 'refresh',
        url: response.url,
        // Notice not all servers return the ETag header. If this is not provided you should use other cache headers or rely on your own means to check if the content has changed.
        eTag: response.headers.get('ETag')
      };

      // Tell the client about the update.
      client.postMessage(JSON.stringify(message));
    });
  });
}

处理“资源已更新”消息

navigator.serviceWorker.onmessage = function (evt) {
  var message = JSON.parse(evt.data);

  var isRefresh = message.type === 'refresh';
  var isAsset = message.url.includes('asset');
  var lastETag = localStorage.currentETag;

  // ETag header usually contains the hash of the resource so it is a very effective way of check for fresh content.
  var isNew =  lastETag !== message.eTag;

  if (isRefresh && isAsset && isNew) {
    // Escape the first time (when there is no ETag yet)
    if (lastETag) {
      // Inform the user about the update.
      notice.hidden = false;
    }
    //For teaching purposes, although this information is in the offline cache and it could be retrieved from the service worker, keeping track of the header in the localStorage keeps the implementation simple.
    localStorage.currentETag = message.eTag;
  }
};