在同一域但不同的文件夹中使用多个 javascript service workers

Using multiple javascript service workers at the same domain but different folders

我的网站为每个客户提供了一系列网络应用程序。每个客户都有不同的应用组合可供使用。

每个网络应用都托管在不同的文件夹中。

所以我只需要为每个客户端缓存允许的 Web 应用程序,而不是缓存所有应用程序,其中许多应用程序是用户根本不会使用的。

我天真地为网站 shell 创建了一个全局服务工作者,并为每个文件夹或应用程序自定义命名服务工作者。

但是我注意到在第一个 service worker 之后 sw_global.js service worker 成功注册、安装、激活、获取并创建了一个名为 cache-global 的缓存,第二个 service worker sw_app1,js,它创建自己的缓存cache-app1,清除所有缓存-global。

如何为每个文件夹使用自定义服务工作者?。请记住,每个文件夹都是一个微服务或 Web 应用程序,并非所有用户都必须允许使用,因此不要缓存来自唯一服务工作者的所有内容。

实际上我在 vanilla.js 上编写代码,没有 angular,没有反应,没有 vue,没有 nada。

这里有两点要记住:

  1. 可以为给定的 origin, as long as each service worker has its own unique scope 注册任意数量的服务工作者。听起来您已经在这样做了,既注册了范围为 / 的顶级服务人员,又注册了范围为每个独立 Web 应用 运行 的路径的其他服务人员。

  2. Cache Storage API (and other storage mechanisms, like IndexedDB) 在整个源中共享,默认情况下没有 "sharding" 或命名空间隔离。

将这两个事实放在一起,我的猜测是,您在其中一个服务工作线程的 activate 处理程序中有一些缓存清理代码,该服务工作线程的作用域是特定的 Web 应用程序,并且该代码检索当前缓存名称的列表并删除它认为已过时的所有缓存。这是 service worker 经常做的事情,但是如果你不考虑 caches.keys() 将 return 列表 所有 源中的缓存,甚至是其他服务工作者实例创建的缓存。

假设这就是这里发生的事情,我建议遵循的模型是在创建缓存时将 registration.scope 的值作为缓存名称的一部分。当需要删除 activate 处理程序中的旧缓存条目时,很容易确保您只清理特定服务人员应该管理的缓存,方法是过滤掉那些不匹配的内容 registration.scope.

例如,像这样:

const CACHE_VERSION = 'v2';
const CACHE_NAME = `${registration.scope}!${CACHE_VERSION}`;

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {
      // Add entries to the cache...
    })
  );
});

self.addEventListener('activate', (event) => {
  const cleanup = async () => {
    const cacheNames = await caches.keys();
    const cachesToDelete = cachesNames.filter(
        (cacheName) => cacheName.startsWith(`${registration.scope}!`) &&
                       cacheName !== CACHE_NAME);
    await Promise.all(cachesToDelete.map(
      (cacheName) => caches.delete(cacheName)));
  };

  event.waitUntil(cleanup());
});

我不知道,但接受的答案对我不起作用,因为它有拼写错误以及我认为缺少的代码。我把对我有用的东西放在下面。虽然我不想从接受的答案中拿走任何功劳,但只是添加一个工作代码,这将帮助其他人。

self.addEventListener('activate', (event) => {
  const cleanup = async () => {
    const cacheNames = await caches.keys();// here it should be caches
    console.log(cacheNames);
    const cachesToDelete = cacheNames.filter(      
    (cacheNames) => (cacheNames.startsWith(`${registration.scope}!`) && cacheNames !== CACHE_NAME));
    console.log(cachesToDelete); 
   // await Promise.all(cachesToDelete.map(caches.delete));// this line rewritten to make it working.
    await Promise.all(cachesToDelete.map(CACHE_NAME=>{ 
      return caches.delete(CACHE_NAME);
    })
    )    
  };  
  event.waitUntil(cleanup());
});