概述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;
}

发表评论 取消回复