简体   繁体   English

在同一个域但不同的文件夹中使用多个 javascript 服务工作者

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

My website offers an array of web apps for each client.我的网站为每个客户提供了一系列网络应用程序。 Each client has a different mix of apps that can be used.每个客户端都有不同的应用程序组合可供使用。

Each web app is a hosted in a different folder.每个 Web 应用程序都托管在不同的文件夹中。

So I need to cache for each client only it's allowed web apps instead of caching all the apps, many of them he the user, will not use at all.所以我只需要为每个客户端缓存它允许的网络应用程序而不是缓存所有的应用程序,其中许多是用户,根本不会使用。

I naively created a global service worker for the shell of the website and custom named service worker for each folder or app.我天真地为网站的外壳创建了一个全局服务工作者,并为每个文件夹或应用程序创建了自定义命名的服务工作者。

However I noticed that after the first service worker, say sw_global.js service worker registers, installs, activates, fetches succesfully and creates a cache named cache-global, the second service worker, say sw_app1,js, which creates it's own cache cache-app1, clears all cache-global.但是我注意到在第一个 service worker 之后,比如说 sw_global.js service worker 注册、安装、激活、获取成功并创建了一个名为 cache-global 的缓存,第二个 service worker,比如说 sw_app1,js,它创建了它自己的缓存缓存 - app1,清除所有缓存全局。

How can I use custom service worker for each folder?.如何为每个文件夹使用自定义 Service Worker? Please keep in mind that each folder is a microservice or a web app which is not necesarilly allowed for all users, so it's imperative to not cache all content from a unique service worker.请记住,每个文件夹都是一个微服务或 Web 应用程序,并非所有用户都必须允许,因此必须不要缓存来自唯一服务工作者的所有内容。

Actually I code on vanilla.js, no angular, no react, no vue, no nada.实际上我在 vanilla.js 上编写代码,没有 angular,没有 react,没有 vue,没有 nada。

There's two things to keep in mind here:这里有两件事要记住:

  1. It's possible to register an arbitrary number of service workers for a given origin , as long as each service worker has its own unique scope .可以为给定的origin注册任意数量的 service worker,只要每个 service worker 都有自己唯一的scope It sounds like you're doing this already, registering both a top-level service worker with a scope of / and then additional service workers scoped to the paths from which each of your independent web apps run.听起来您已经在这样做了,注册了一个范围为/的顶级服务工作者,然后注册了范围为每个独立 Web 应用程序运行路径的其他服务工作者。

  2. The Cache Storage API (and other storage mechanisms, like IndexedDB ) are shared throughout the entire origin, and by default there's no "sharding" or namespace segregation. 缓存存储 API (和其他存储机制,如IndexedDB )在整个源中共享,默认情况下没有“分片”或命名空间隔离。

Taking those two facts together, my guess is that what's happening is that you have some cache cleanup code in the activate handler of one of the service workers that's scoped to a specific web app, and that code retrieves a list of current cache names and deletes any caches that it thinks is out of date.将这两个事实放在一起,我的猜测是发生的事情是您在一个服务工作线程的activate处理程序中有一些缓存清理代码,该处理程序的范围限定为特定的 Web 应用程序,并且该代码检索当前缓存名称和删除的列表它认为已过时的任何缓存。 That's a common thing to do in a service worker, but you can run into trouble if you don't take into account the fact that caches.keys() will return a list of all the caches in your origin, even the caches that were created by other service worker instances.这是在 Service Worker 中很常见的事情,但是如果您不考虑caches.keys()将返回源中所有缓存的列表,甚至是caches.keys()的缓存,您可能会遇到麻烦由其他服务工作者实例创建。

Assuming that's what's going on here, a model that I'd recommend following is to include the value of registration.scope as part of the cache name when you create your caches.假设这就是这里发生的事情,我建议遵循的模型是在创建缓存时将registration.scope的值包含为缓存名称的一部分。 When it comes time to delete old cache entries in your activate handler, it's easy to make sure that you're only cleaning up caches that your specific service worker is supposed to manage by filtering out those that don't match registration.scope .当需要删除activate处理程序中的旧缓存条目时,很容易通过过滤掉那些与registration.scope不匹配的缓存来确保您只清理您的特定服务工作者应该管理的缓存。

Eg, something like this:例如,这样的事情:

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());
});

I don't know, but the accepted answer didn't worked for me as it has typos as wells missing code I think.我不知道,但接受的答案对我不起作用,因为它有拼写错误以及我认为缺少代码。 I am putting below what worked for me.我把对我有用的东西放在下面。 Though I don't want to take away any credit from the accepted answer, but just adding a working code, which will help others.虽然我不想从接受的答案中拿走任何功劳,但只是添加一个工作代码,这将有助于其他人。

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());
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM