प्रोग्रेसिव फ़ाइल अपलोड: UX और तकनीकी गाइड
बेहतर यूज़र अनुभव के लिए ड्रैग-एंड-ड्रॉप, प्रोग्रेस बार और सुगम एरर हैंडलिंग के साथ प्रोग्रेसिव फ़ाइल अपलोड अनुभव बनाएँ।
प्रोग्रेसिव फ़ाइल अपलोड users को हर stage पर तुरंत, भरोसेमंद feedback देता है: जिस पल वे file drop करते हैं, selection confirmation; upload के दौरान, realistic ETA के साथ smooth progress bar; failure पर, specific retry options; completion के बाद, next actions के साथ clear success state। Technical ingredients हैं HTML5 DataTransfer API के माध्यम से drag-and-drop, resumability के साथ chunked uploads, byte-accurate progress के लिए ReadableStream के साथ fetch streaming, और IndexedDB के माध्यम से tab reloads survive करने वाला state management। ठीक से किया जाए तो 5 GB file upload करने वाला user कभी नहीं सोचेगा कि app freeze है।
"Progressive" का वास्तविक अर्थ
Progressive का दो अर्थ है। एक: progressive enhancement — upload plain <input type="file"> POST के रूप में 2012 के browser पर काम करता है, और JavaScript available होने पर drag-and-drop, chunking, और retries मिलते हैं। दो: progressive disclosure — UI complexity केवल जरूरत पर reveal करता है — upload के दौरान percentage दिखाएं, लेकिन retry details केवल failure पर। दोनों अर्थ एक ही principle की ओर इशारा करते हैं: user को कभी dead end नहीं मिलनी चाहिए, और information के बिना कभी wait नहीं करना चाहिए।
टालने वाला failure mode है "spinner of doom" — एक generic loading animation जो progress, ETA, या कुछ गलत होने का कोई indication नहीं देता। Users वे uploads cancel करते हैं जिन पर उन्हें भरोसा नहीं।
ऐसा Drag-and-Drop जो Browser से लड़े नहीं
HTML5 drag-and-drop API bugs के लिए बदनाम है। कुछ rules जो इसे tolerable बनाते हैं:
const dropzone = document.querySelector('.dropzone');
dropzone.addEventListener('dragover', (e) => {
e.preventDefault();
dropzone.classList.add('dragging');
});
dropzone.addEventListener('dragleave', () => {
dropzone.classList.remove('dragging');
});
dropzone.addEventListener('drop', (e) => {
e.preventDefault();
dropzone.classList.remove('dragging');
handleFiles([...e.dataTransfer.files]);
});
dragover पर preventDefault call करें या drop target drop accept नहीं करेगा। Folders को webkitGetAsEntry() के माध्यम से accept करने के लिए files के बजाय e.dataTransfer.items उपयोग करें — Chrome और Firefox पर directory contents recursively capture करने का यही एकमात्र तरीका है।
Fallback भी usable बनाएं: styled <input type="file" multiple> wrap करने वाला visible <label> keyboard और screen reader navigation सहित 100% users के लिए काम करता है।
ऐसा Progress दिखाएं जिस पर Users भरोसा करें
Progress bars तीन कारणों से jump करती हैं: uneven chunk sizes, TCP slow-start, और network stack में buffering। 2-second trailing average से smooth करें:
const samples = []; // [{ time, bytes }]
function recordSample(bytes) {
const now = performance.now();
samples.push({ time: now, bytes });
while (samples.length > 1 && now - samples[0].time > 2000) samples.shift();
}
function throughput() {
if (samples.length < 2) return 0;
const delta = samples[samples.length - 1];
const base = samples[0];
return (delta.bytes - base.bytes) / ((delta.time - base.time) / 1000);
}
ETA को (totalBytes - uploadedBytes) / throughput() के रूप में calculate करें, display को कम से कम 5 seconds पर clamp करें, और human terms में format करें: "लगभग 2 मिनट" न कि "124.3 seconds।" Percentage और byte counter दोनों दिखाएं ("340 MB of 2.1 GB") — users दोनों cross-check करते हैं जब कुछ गलत लगता है।
Actionable Recovery के साथ Error States
Generic "upload failed" messages trust destroy करते हैं। Failures को पाँच buckets में classify करें और प्रत्येक को distinctly surface करें:
- Network drop (offline event, TCP reset): "Reconnecting..." automatic retry के साथ
- Server 5xx: "Server error, 5s में retry" manual retry button के साथ
- Server 4xx (413 too large, 415 bad type): "File rejected: too large" file replacement के साथ
- Auth expired (401, 403): "Session expired, continue करने के लिए sign in करें"
- Client crash (JS error, browser killed tab): Reload पर IndexedDB से Recovery
Message के साथ वह एक action pair करें जो इसे resolve करता है। यदि user offline है, तो navigator.onLine और online event के माध्यम से monitor किया गया online/offline state दिखाएं।
Fetch Streams के साथ Bytes Track करना
XMLHttpRequest.upload.onprogress upload progress track करने का traditional तरीका रहा है, लेकिन HTTP/3 पर flaky है और send buffer में queued bytes miss करता है। Modern approach bytes count करने के लिए ReadableStream उपयोग करता है जैसे वे produce होते हैं:
function trackedStream(blob, onBytes) {
let sent = 0;
return new ReadableStream({
async pull(controller) {
const reader = blob.stream().getReader();
while (true) {
const { done, value } = await reader.read();
if (done) { controller.close(); return; }
sent += value.byteLength;
onBytes(sent);
controller.enqueue(value);
}
}
});
}
Stream को duplex: 'half' के साथ fetch को body के रूप में pass करें। Request streams के लिए Safari support 17.4 में आया; उससे पहले, XMLHttpRequest पर fall back करें। यह network stack को actually hand किए गए bytes से tied millisecond-accurate progress देता है।
Pause, Resume, और Cancel
Users एक minute से अधिक लेने वाली किसी भी चीज़ पर pause button expect करते हैं। Chunked uploads के साथ, pause बस "नए chunks dispatch करना बंद करना" है, और resume काम की queue जहाँ छूटी वहाँ से pick up करता है। Cancel AbortController उपयोग करता है:
const ctrl = new AbortController();
cancelButton.onclick = () => ctrl.abort();
await fetch(url, { method: 'PUT', body: blob, signal: ctrl.signal });
Abort पर, cleanup करें: server पर upload session DELETE करें ताकि storage leak न हो, IndexedDB entry clear करें, initial state पर return करें। Pause state preserve करना चाहिए; cancel destroy करना चाहिए। Distinction को UI में visible बनाएं।
Tab Reloads Survive करना
प्रत्येक successful chunk के बाद upload state persist करें:
await idb.put('uploads', {
sessionId, fileFingerprint, fileName, fileSize,
completedChunks: [...done], updatedAt: Date.now()
}, sessionId);
Fingerprint file के पहले 1 MB का SHA-256 है plus size और lastModified — reload के बाद user फिर से pick करने पर file re-identify करने के लिए पर्याप्त। Page load पर, एक घंटे से कम पुराने sessions के लिए IndexedDB check करें और resumption offer करें: "12 मिनट पहले एक upload progress में था। Resume करें?" Consent के बिना auto-resume न करें — users कभी-कभी specifically cancel करने के लिए reload करते हैं।
Accessible और Keyboard-Friendly Interactions
ऐसा dropzone जो केवल mouse drags पर respond करता है screen reader और keyboard users के लिए fail होता है। Add करें:
- Dropzone पर
role="button"औरtabindex="0" - Enter/Space key handler जो file input click करता है
- Screen readers को milestones announce करने के लिए progress region पर
aria-live="polite" - Visible focus styles, केवल hover नहीं
- Clear labels — "फ़ाइल अपलोड करें" "Browse" से बेहतर है जो bare icon से बेहतर है
Keyboard testing fast है: 10 मिनट के लिए mouse unplug करें और upload complete करने की कोशिश करें। यदि आप नहीं कर सकते, तो आपके users का एक हिस्सा भी नहीं कर सकता।
HexaTransfer का uploader exactly यह progressive pattern उपयोग करता है — plain-form fallback, drag-and-drop enhancement, fetch streaming, IndexedDB-backed resume, और specific error recovery। hexatransfer.com पर मुफ्त में आज़माएं — कोई खाता नहीं, 10 GB अधिकतम।
वे Details जो Users वास्तव में Notice करते हैं
Forgettable uploaders और great uploaders के बीच polish छोटे moments में रहती है: एक drop animation जो confirm करती है कि file capture हुई, एक progress bar जो jump करने के बजाय smoothly fill होती है, एक ETA जो wildly flip होने के बजाय समय के साथ अधिक accurate होती है, specific error messages जो बताते हैं आगे क्या करना है, accidental refresh के बाद resume prompt, एक completion state जो share link copy करने के लिए पर्याप्त समय persist करती है, और cancel behavior जो upload तुरंत रोकता है। इनमें से प्रत्येक कुछ lines of code है। सभी ship करें और आपका uploader default <input type="file"> treatment से एक order of magnitude बेहतर feel करता है।
एंड-टू-एंड एन्क्रिप्शन के साथ बड़ी फ़ाइलें सुरक्षित रूप से भेजें
एंड-टू-एंड एन्क्रिप्शन के साथ 10 GB तक की फ़ाइलें मुफ़्त में ट्रांसफ़र करें। अकाउंट की आवश्यकता नहीं। अपलोड से पहले आपकी फ़ाइलें ब्राउज़र में एन्क्रिप्ट की जाती हैं — कोई और उन्हें पढ़ नहीं सकता।
फ़ाइल भेजें