0

我有一个PWA,它本质上是一个图书阅读器。因此,它需要大量的数据(即书籍文本)来操作。当由Lighthouse分析时,它在页面加载检查中得分很低。

我的问题是:我可以采用哪些方法来改善页面加载,同时仍确保离线功能?

我可以有一个最小的起始页(例如,只显示“请稍候,正在下载文本”消息),然后动态下载(通过注入的脚本标签或 AJAX)JSON 数据文件。但是,我不确定随后如何确保从缓存中获取数据。

只是想知道其他人是如何处理这个问题的......

4

1 回答 1

0

由于这个问题已经成为风滚草,我决定发布我的尝试结果。

根据Jake 的文章,我使用以下脚本和 Chrome DevTools 来研究 service worker 事件:

'use strict';

let container = null;
let updateFound = false;
let newInstall = false;

window.onload = () => {
  container = document.querySelector('.container');
  let loading = document.createElement('div');
  loading.classList.add('loading');
  loading.innerHTML = 'Downloading application.<br>Please wait...';
  container.appendChild(loading);
  console.log(`window.onload:      ${Date.now()}`);
  swEvents();
};

let swEvents = () => {
  if (navigator.serviceWorker) {
    navigator.serviceWorker.ready.then(() => {
      console.log(`sw.ready:           ${Date.now()}`);
      if (!updateFound) {
        loadApp();
        return;
      }
      newInstall = true;
      console.log(`new install:        ${Date.now()}`);
    }).catch((error) => {
      console.log(`sw.ready error: ${error.message}`);
    });
  }

  navigator.serviceWorker.register('/sw.js').then((reg) => {
    reg.onupdatefound = () => {
      updateFound = true;
      console.log(`reg.updatefound:    ${Date.now()}`);
      const newWorker = reg.installing;
      newWorker.onstatechange = (event) => {
        if (event.target.state === 'activated') {
          console.log(`nw.activated:       ${Date.now()}`);
          if (newInstall) {
            loadApp();
            return;
          }
          refresh();
        }
      };
    };
  }).catch((error) => {
    console.log(`reg.error: ${error.message}`);
  });
};

let refresh = () => {
  console.log(`refresh():          ${Date.now()}`);
  // window.location.reload(true);
};

let loadApp = () => {
  console.log(`loadApp():          ${Date.now()}`);
  let child;
  while (child = container.firstChild) {
    container.removeChild(child);
  }
  let message = document.createComment('p');
  message.textContent = 'Application loading';
  container.appendChild(message);
  let tag = document.createElement('script');
  tag.src = './app.js';
  document.body.appendChild(tag);
};

一路走来,我了解到,一旦注册了 service worker,它就会立即开始下载所有缓存的资源。我曾假设资源仅在页面加载后才被缓存。我还发现了一些明确的事件模式来指示正在发生的生命周期阶段。

对于新安装,上述脚本中记录了以下事件:

window.onload -> reg.updatefound -> sw.ready -> nw.activated

对于这种情况,当sw.ready触发时,所有资源都已被缓存。此时,我可以将应用从“请稍候”阶段切换并动态加载缓存资源并启动应用。

对于简单的页面刷新,将记录以下事件:

window.onload -> sw.ready

如果应用程序已经下载并且没有可用的更新,这将是事件序列。此时,我可以再次切换阶段并启动应用程序。

对于服务工作者脚本更新后的页面刷新,将记录以下事件:

window.onload -> sw.ready -> reg.updatefound -> nw.activated

在这种情况下,当nw.activated触发时,所有缓存的资源都已更新。需要再次刷新页面才能实际加载更改。此时,可能会提示用户进行更新。或者应用程序将在下次启动时自行更新。

通过跟踪这些事件模式,很容易判断 Service Worker 处于哪个生命周期阶段并采取适当的措施。

于 2019-06-29T21:04:10.023 回答