You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Progressive Web App使用Service Worker实现资源分组渐进式缓存方法问询

实现方案

核心逻辑是通过 postMessage 实现主线程和 Service Worker 之间的通信,主线程发送预缓存指令,Service Worker 收到后执行对应关卡资源的缓存逻辑。


第一步:扩展 Service Worker 代码,新增消息监听

在原有 Service Worker 代码基础上,新增消息事件监听,处理预缓存请求:

// 原有代码保留
self.addEventListener("fetch", event => {
  event.respondWith( caches.match(event.request)
    .then( cachedResponse => {
      return cachedResponse || fetch(event.request);
    } )
  );
});

const cacheName0 = "bare-bones-of-the-app";
const mainResourcesToPrecache = [
"index.html",
"app.js",
"style.css"
];

self.addEventListener("install", event => {
  event.waitUntil(
    caches.open(cacheName0).then(cache => {
      return cache.addAll(mainResourcesToPrecache);
    })
  );
});

// ========== 新增代码开始 ==========
// 监听主线程发来的消息
self.addEventListener('message', event => {
  // 只处理预缓存关卡的指令
  if (event.data?.type === 'PRECACHE_LEVEL') {
    const { levelId, resources } = event.data.payload;
    const cacheName = `level-${levelId}`;
    
    // 等待缓存逻辑执行完成
    event.waitUntil(
      caches.open(cacheName)
        .then(cache => cache.addAll(resources))
        .then(() => {
          // 缓存成功后给主线程回传通知
          event.source.postMessage({
            type: 'PRECACHE_SUCCESS',
            payload: { levelId }
          });
        })
        .catch(err => {
          // 缓存失败回传错误信息
          event.source.postMessage({
            type: 'PRECACHE_FAILED',
            payload: { levelId, error: err.message }
          });
        })
    );
  }
});
// ========== 新增代码结束 ==========

第二步:主线程封装预缓存触发函数

在主线程代码中封装调用方法,主动向 Service Worker 发送预缓存指令:

// 主线程预缓存触发函数
async function precacheLevelResources(levelId, resources) {
  // 等待Service Worker激活完成
  const registration = await navigator.serviceWorker.ready;
  const activeSW = registration.active;
  
  if (!activeSW) {
    throw new Error('Service Worker 尚未激活,无法预缓存资源');
  }

  // 异步等待Service Worker返回处理结果
  return new Promise((resolve, reject) => {
    const messageHandler = (event) => {
      // 匹配当前关卡的处理结果
      if (event.data?.payload?.levelId !== levelId) return;

      if (event.data.type === 'PRECACHE_SUCCESS') {
        navigator.serviceWorker.removeEventListener('message', messageHandler);
        resolve();
      }
      if (event.data.type === 'PRECACHE_FAILED') {
        navigator.serviceWorker.removeEventListener('message', messageHandler);
        reject(new Error(event.data.payload.error));
      }
    };

    navigator.serviceWorker.addEventListener('message', messageHandler);

    // 发送预缓存指令
    activeSW.postMessage({
      type: 'PRECACHE_LEVEL',
      payload: { levelId, resources }
    });
  });
}

第三步:业务场景调用

可以根据游戏进度选择合适的触发时机,比如用户通关当前关卡时,提前加载下一关资源:

// 示例:用户通关第1关后,预加载第2关资源
const resourcesForLevel2 = [
  "anotherpicture.jpg",
  "anotherartwork.png",
  "anothersound.mp3"
];

precacheLevelResources(2, resourcesForLevel2)
  .then(() => {
    console.log('第2关资源预加载完成,可直接进入');
  })
  .catch(err => {
    console.error('第2关资源预加载失败:', err);
    // 可在这里添加重试逻辑
  });

补充说明

  • 触发时机可灵活调整,比如用户当前关卡进度达到80%时就提前触发预加载,进一步减少用户等待时间
  • 如果关卡资源体积较大,可拆分分批加载,避免占用过多带宽影响当前关卡的正常运行
  • 不需要的旧关卡资源可主动触发删除,节省用户设备存储空间

内容的提问来源于stack exchange,提问作者BulliedByModeratorsAgain_Again

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 09:06:08