You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Service Worker Sync事件未触发,离线评论同步异常求助

我来帮你排查这个Sync事件不触发的问题,你怀疑链式Promise的问题确实很有道理,咱们一步步拆解来看:

1. 先修正event.waitUntil的错误处理逻辑

你代码里的.catch挂在waitUntil外面,这会导致错误无法被Service Worker的同步机制正确捕获。waitUntil需要接收一个能准确反映同步任务状态的Promise——如果任务失败但你没把错误传递回去,浏览器会误以为同步已经完成,自然不会在联网后重试触发。

把错误处理移到waitUntil的Promise链内部,并且注意非最后一次机会时要重新抛出错误

self.addEventListener('sync', event => {
  if (event.tag === 'outbox') {
    event.waitUntil(
      postReview()
        .catch(err => {
          if (event.lastChance) {
            // 最后一次重试机会,通知用户失败
            return self.registration.showNotification('评论同步失败,已无法重试', { 
              body: err.message 
            });
          }
          // 不是最后一次,抛出错误让浏览器标记任务未完成,下次联网重试
          throw err;
        })
    );
  }
});

2. 确保postReview的Promise链完整覆盖所有异步操作

postReview里的IndexedDB读写、网络请求必须全部正确链式返回Promise,不能有遗漏的异步任务:

  • 用Promise封装IndexedDB操作(避免回调嵌套)
  • 发送评论后,删除本地数据的操作也要加入Promise链
  • 等待数据库事务完成再返回

举个规范的postReview示例:

async function postReview() {
  // 封装的IndexedDB打开方法(返回Promise)
  const db = await openOutboxDB();
  const tx = db.transaction('outbox', 'readwrite');
  const store = tx.objectStore('outbox');
  const offlineReviews = await store.getAll();

  // 逐个发送评论,确保每个操作都等待完成
  for (const review of offlineReviews) {
    await fetch('/api/submit-review', {
      method: 'POST',
      body: JSON.stringify(review),
      headers: { 'Content-Type': 'application/json' }
    });
    // 发送成功后删除本地缓存
    await store.delete(review.id);
  }

  // 必须等待事务完成,否则可能出现数据不一致
  await tx.complete;
  return;
}

如果这里有未等待的异步操作,waitUntil会提前结束,浏览器会误判同步任务已完成。

3. 检查Sync事件的注册时机

离线提交评论后,必须立即注册sync事件,而不是只在Service Worker初始化时注册。页面端的提交逻辑应该是这样的:

// 页面端提交评论的代码
async function submitUserReview(reviewContent) {
  try {
    // 先尝试直接提交
    await fetch('/api/submit-review', {
      method: 'POST',
      body: JSON.stringify({ content: reviewContent })
    });
  } catch (err) {
    // 离线状态,保存到IndexedDB
    await saveToOfflineOutbox({ content: reviewContent });
    // 注册同步事件(重复注册会自动去重,不用担心重复任务)
    await navigator.serviceWorker.ready.then(reg => reg.sync.register('outbox'));
  }
}

如果没在保存评论后注册sync,浏览器没有待处理的同步任务,联网后自然不会触发事件。

4. 用DevTools验证同步任务状态

你可以在Chrome DevTools里确认是否有待处理的sync任务:
打开ApplicationService Workers → 找到你的Service Worker → 点击Sync标签,查看是否有outbox标签的任务。

  • 如果没有:说明sync事件没被正确注册,检查页面端的注册逻辑
  • 如果有:问题大概率出在waitUntil的Promise处理上

核心问题通常就是这几点:错误没正确抛出导致浏览器误判任务完成、异步操作没链式处理、或者sync事件没及时注册。按上面的步骤调整应该就能解决问题。

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

火山引擎 最新活动