如何通知我的应用程序正在接收来自服务人员的缓存响应?

时间:2018-08-16 21:41:39

标签: javascript service-worker

我想使用服务工作者来缓存用户离线或我的应用程序后端关闭时可以使用的响应。出于用户体验的原因,我想向用户显示一条通知,告知您当前无法访问该应用程序的后端,而正在提供缓存的内容。最好的方法是什么?我可以在服务工作者中向响应添加标头,但是我不确定这是否是“正确的方法”……似乎应该有一个更简单的模式。这是我的服务人员代码:

self.addEventListener('fetch', event => {
  console.log(`fetch event`, event);
  event.respondWith(doFetch(event.request));
});

// fetch from network, fallback to cache
function doFetch(request) {
  return fetch(request)
    .then(response => {
      return caches.open(CACHE)
        .then(cache => {
          cache.put(request, response.clone());
          return response;
        })
    })
    .catch(error => {
      console.warn(`fetch to ${request.url} failed`, error);
      return fromCache(request);
    });
}

function fromCache(request) {
  return caches.open(CACHE)
    .then(cache => cache.match(request))
    .then(match => {
      if (match) {
        // response.clone doesn't work here because I need to modify it
        return cloneResponse(match);
      } else {
        throw new Error(`no match for ${request.url}`);
      }
    });
}
// this clones a response in a way that let's me modify it
function cloneResponse(response) {
  let init = {
    status: response.status,
    statusText: response.statusText,
    headers: { 'X-From-SW-Cache': 'true' }
  };

  response.headers.forEach((v, k) => {
    init.headers[k] = v;
  });

  return response.text().then((body) => new Response(body, init));
}

1 个答案:

答案 0 :(得分:0)

在响应中添加标头绝对是一个选择。

要考虑的另一种选择是使用postMessage()将消息发送到客户端页面,让其知道正在使用缓存的响应。如果您想在重新使用网络后切换某些UI元素,则可以扩展该逻辑以向客户端发送一条消息,让其知道何时使用网络响应。

以下是在您的服务人员中实现这一目标的代码:

async function postToClient(clientId, message) {
  const client = await clients.get(clientId);
  client.postMessage(message);
}

async function responseLogic(event) {
  const cache = await caches.open('cache-name');
  try {
    const response = await fetch(event.request);
    await cache.put(event.request, response.clone());
    event.waitUntil(postToClient(event.request.clientId, 'FROM_NETWORK'));
    return response;
  } catch (error) {
    const cachedResponse = await cache.match(event.request);
    if (cachedResponse) {
      event.waitUntil(postToClient(event.request.clientId, 'FROM_CACHE'));
      return cachedResponse;
    }
    throw error;
  }
}

self.addEventListener('fetch', (event) => {
  // Check to see if this is a request for your API:
  if (event.request.url === 'https://example.com/api') {
    event.respondWith(responseLogic(event));
  }
});

然后在您的客户端页面上,您可以注册message侦听器以通过显示或隐藏一些UI元素来响应来自服务工作者的消息,具体取决于最后的响应是来自网络还是来自缓存:

navigator.serviceWorker.addEventListener('message', (event) => {
  if (event.data === 'FROM_NETWORK') {
    // Do something in your UI.
  } else if (event.data === 'FROM_CACHE') {
    // Do something in your UI.
  }
});