javascript - 如何创建一个简单的服务 worker 来添加新项目以离线缓存?

标签 javascript webpack ecmascript-6 browser-cache service-worker

我想从一个简单的 API 获取响应,用它来创建一系列 URL(一个数组),然后我想将其提供给服务 worker ,并让它将每个条目添加到离线存储中。

作为背景,我对 sw-precache (sw-precache-webpack-plugin)、sw-toolbox 和一般 JavaScript 的经验有限,尽管这种情况正在发生变化。目前有一个 webpack + vue 设置从我很久以前构建的一个简单 API 获取数据。

访问我网站的用户可能希望离线使用一种或多种类型的内容 - 这可能需要 30 个请求(30 个单独的 URL)添加到缓存,最多 4000 个以上。上限预计会随着时间的推移而增加。以我之前尝试过的方式运行 Cache.addAll() 会使客户端崩溃 - 一次请求太多。我认为 importScripts 选项可能是我需要的东西,但我不确定从哪里开始。我如何编写一个脚本来作为我可以向其发送数组的服务 worker 的补充?

总结:

  • 使用 webpack/vue
  • 基本熟悉 sw-precache 和 sw-toolkit
  • 需要在一个用户请求中缓存数万到数千个页面
  • 想知道如何着手开发解决方案 问题,例如 importScripts 的示例代码片段,或 另一个可以解决问题的 webpack 插件,或其他替代方案 包含 Service Worker 的方法。

开发代码:https://laoadventist.info

用于获取缓存 URL 的简单 API:https://laoadventist.info/api/r2

我想缓存的单个示例 API 结果(单击一个按钮需要数万个请求):.../api/d

更新:

我能够想出一个有点实用的解决方案......它并不完美,或者在 service worker 中,但它确实有效。欢迎提出改进建议。

var temparray
var tempposition

let processCache = function (array, position) {
  if (typeof array === 'undefined') {
    array = []
  }
  if (array.length > 0) {
    let chunk = array.shift()
    temparray = array
    tempposition = position
    caches.open('testing')
      .then((cache) => { cache.addAll([chunk]) })
      .then(function () { processCache(temparray, tempposition) })
  }
}

最佳答案

选项1:使用webpack

Webpack 用户可以从 webpack-offline-plugin 中受益它维护得很好,工作也很好。但是,在运行时您仍然需要为动态缓存编写一些代码。对于动态缓存,请引用插件维护者的建议:here

选项 2:自己制作

在你的主包文件中注册 Service Worker

假设:您的服务 worker 文件名为 sw.js,它位于您网站的根文件夹中。

if ('serviceWorker' in navigator) {
  // Recommended to register onLoad
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('/sw.js');
  });
}

sw.js 中:安装静态

self.addEventListener('install', function(event) {
  self.skipWaiting();
  event.waitUntil(
    caches.open('static-files-v1').then(function(cache) {
      return cache.addAll(['/', 'someFile.js', 'someFile.css']);
    })
  );
});

sw.js 中:获取已安装的静态数据

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request)
    })
  );
});

更多高级步骤

sw.js 中:在获取时缓存动态 URL

fetch 事件将监听通过 HTTPS 获取到您网站的任何内容,请阅读我的评论以帮助理解 snipper。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.open('dynamic-content-v1').then(function(cache) {
      // check if the requested URL is inside the dynamic-content-v1
      return cache.match(event.request).then(function (response) {
        // when found, respond with it.
        // when not found: return it as it is after taking a clone
        // and storing it, so next visit to the URL it will be there
        return response || fetch(event.request).then(function(response) {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    })
  );
});

默认情况下,这种方法不是一个很好的做法,特别是如果您有数千个页面、内容和图像。您不想让用户膨胀并使用您所有的缓存存储配额。请考虑仅缓存要首先显示的重要内容并保持最新,因为您不想发送过时的信息。

选项3和重要说明:

重要提示:您不需要软件即可将动态内容添加到缓存 API。他们都是两个不同的东西。随意从框架组件\异步路由或其他任何内容中获取并添加到缓存 API。

对您的 fiddle 的建议和建议:

我不太确定我是否 100% 了解您在做什么。我可以看到递归函数,但不确定您为什么需要它或其中发生了什么。以下是有关如何从组件内部动态缓存的片段:

// in case browser doesn't support cache
var URL_2_CACHE = '/content/important.html';
if (!('caches' in window)) return;
fetch(new Request(URL_2_CACHE)).then(function(response){
return caches.open('dynamic-cahce-v1').then(function(cache) {
    // DONE!
    return cache.put(URL_2_CACHE, response);
  });
});

现在 HTML 页面已存储在缓存中,SW 将在下一次请求时从那里获取它。

关于javascript - 如何创建一个简单的服务 worker 来添加新项目以离线缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43905334/

相关文章:

javascript - 如果 xx 存在,则执行 yy

javascript - Material UI/Webpack/React - 生产模式下的类名优化/缩小

javascript - 如何在运行时在此类中更改类的原型(prototype)(使用 ES6 类)

javascript动态导入类模块并获取类名

javascript - 数据准备好后如何渲染组件?

javascript - 从 Controller 调用指令

javascript - 如何从对象重命名字段

javascript - 如何在 webpack-dev-server 和express 服务器上重新加载模块?

css - 网络包 4 : How to get CSS source maps working with LESS?

javascript - this.State 未定义