如何用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
相关产品推荐
相关产品推荐

