概述WebSocket 提供低延迟双向通道。本文给出二进制分块上传与确认协商,并结合 IndexedDB 保存进度以实现断线恢复。分块上传与确认function supportsWS() { return typeof WebSocket === 'function'; } async function* chunkFile(file, size) { let o = 0; while (o < file.size) { const b = file.slice(o, o + size); const ab = await b.arrayBuffer(); yield new Uint8Array(ab); o += size; } } async function uploadWS(url, file, size = 1024 * 512) { if (!supportsWS()) throw new Error('ws not supported'); const ws = new WebSocket(url); await new Promise(resolve => { ws.binaryType = 'arraybuffer'; ws.onopen = resolve; }); let idx = await loadProgress(file.name); ws.onmessage = async e => { const msg = JSON.parse(new TextDecoder().decode(new Uint8Array(e.data))); if (msg.type === 'ack') { idx = idx + 1; await saveProgress(file.name, idx); } }; let i = 0; for await (const chunk of chunkFile(file, size)) { if (i < idx) { i++; continue; } const payload = JSON.stringify({ type: 'chunk', index: i, name: file.name }); const head = new TextEncoder().encode(payload); const merged = new Uint8Array(head.length + chunk.length); merged.set(head, 0); merged.set(chunk, head.length); ws.send(merged); i++; } } 进度持久化function openDB(name) { return new Promise((resolve, reject) => { const r = indexedDB.open(name, 1); r.onupgradeneeded = () => { const db = r.result; if (!db.objectStoreNames.contains('up')) db.createObjectStore('up'); }; r.onsuccess = () => resolve(r.result); r.onerror = () => reject(r.error); }); } async function saveProgress(key, value) { const db = await openDB('wsup'); const tx = db.transaction('up', 'readwrite'); tx.objectStore('up').put(value, key); await new Promise((resolve, reject) => { tx.oncomplete = resolve; tx.onerror = () => reject(tx.error); }); db.close(); } async function loadProgress(key) { const db = await openDB('wsup'); const tx = db.transaction('up', 'readonly'); const req = tx.objectStore('up').get(key); const val = await new Promise((resolve, reject) => { req.onsuccess = () => resolve(req.result || 0); req.onerror = () => reject(req.error); }); db.close(); return val; }

发表评论 取消回复