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

如何用legend-state与Supabase处理本地优先应用的离线文件上传?

本地优先Supabase应用结合Legend-State处理离线/重连文件上传方案

核心思路

离线时利用Legend-State的本地持久化能力暂存待上传文件队列,恢复网络连接后自动触发上传;上传失败的文件移入失败队列,支持手动重试,全程通过Legend-State维护状态同步。


具体实现步骤

1. 初始化本地持久化的上传队列

用Legend-State的persist插件将待上传队列持久化到本地,确保刷新或重启应用后队列不丢失:

import { observable, persist } from '@legendapp/state';

// 队列包含待上传、上传失败两类任务,每个任务存文件、目标路径、唯一ID
const uploadQueue = observable(
  {
    pending: [],
    failed: []
  },
  persist({ name: 'supabase-upload-queue' })
);

2. 拦截上传请求,离线时存入队列

用户选择文件后,先判断网络状态,离线时直接加入待上传队列,在线则立即上传:

function handleFileSelect(file, targetStoragePath) {
  if (!navigator.onLine) {
    uploadQueue.pending.push({
      file: file,
      path: targetStoragePath,
      id: crypto.randomUUID(),
      retryCount: 0
    });
    return;
  }
  // 在线状态直接执行上传
  executeSupabaseUpload(file, targetStoragePath);
}

3. 监听网络重连,自动触发队列上传

监听浏览器online事件和Supabase实时连接状态,恢复连接后批量处理待上传任务:

// 监听浏览器网络恢复
window.addEventListener('online', processPendingUploads);

// 监听Supabase服务重连(更精准,避免浏览器在线但服务不可达的情况)
supabase.realtime.onReconnected(processPendingUploads);

async function processPendingUploads() {
  const pendingTasks = [...uploadQueue.pending.get()];
  for (const task of pendingTasks) {
    try {
      await executeSupabaseUpload(task.file, task.path);
      // 上传成功,从队列移除
      uploadQueue.pending.remove(task.id);
    } catch (err) {
      // 上传失败,移至失败队列
      uploadQueue.pending.remove(task.id);
      uploadQueue.failed.push({ ...task, retryCount: task.retryCount + 1 });
    }
  }
}

4. 封装Supabase上传逻辑

统一处理Supabase存储上传的错误,便于复用和错误捕获:

async function executeSupabaseUpload(file, storagePath) {
  const { error } = await supabase.storage
    .from('your-bucket-name')
    .upload(storagePath, file, {
      cacheControl: '3600',
      upsert: false // 禁止覆盖已有文件,根据需求调整
    });

  if (error) throw new Error(`上传失败: ${error.message}`);
}

5. 失败任务的手动重试机制

给用户提供重试失败上传的入口,限制重试次数避免无限循环:

async function retryFailedTask(taskId) {
  const task = uploadQueue.failed.find(t => t.id === taskId);
  if (!task) return;

  try {
    await executeSupabaseUpload(task.file, task.path);
    uploadQueue.failed.remove(taskId);
  } catch (err) {
    task.retryCount += 1;
    if (task.retryCount >= 3) {
      // 超过重试次数,提示用户手动干预
      alert(`文件 ${task.file.name} 多次上传失败,请检查网络或文件后重试`);
    }
  }
}

关键注意事项

  • 大文件处理:Legend-State默认用localStorage持久化,存储大文件Blob会受限。建议自定义持久化器使用IndexedDB存储文件,或仅存储文件元数据(如文件名、大小、临时路径),上传时重新读取文件。
  • 避免重复上传:通过唯一ID标记队列任务,上传前检查任务是否已存在于队列中。
  • 状态同步:利用Legend-State的响应式特性,将队列状态绑定到UI,实时展示待上传、失败任务的数量和详情。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 03:27:23