İçeriğe atla
HexaTransfer
Bloga dön
Teknik incelemeler

Aşamalı Dosya Yükleme: UX ve Teknik Rehber

Daha iyi kullanıcı deneyimi için sürükle-bırak, ilerleme çubukları ve zarif hata yönetimiyle aşamalı dosya yükleme deneyimleri inşa edin.

Aşamalı bir dosya yükleme, her aşamada kullanıcıya anında ve güvenilir geri bildirim sunar: dosyayı bıraktıkları an seçim onayı; yükleme sırasında gerçekçi bir tahmini süreyle birlikte düzgün bir ilerleme çubuğu; hata durumunda spesifik yeniden deneme seçenekleri; tamamlandığında ise sonraki adımları gösteren net bir başarı ekranı. Teknik bileşenler şunlardır: HTML5 DataTransfer API üzerinden sürükle-bırak, devam ettirilebilirlik özellikli parçalı yüklemeler, bayt doğruluğunda ilerleme için ReadableStream kullanan fetch akışı ve sekme yenilemeleri karşısında IndexedDB üzerinden ayakta kalan durum yönetimi. Doğru yapıldığında, 5 GB dosya yükleyen bir kullanıcı uygulamanın donup donmadığını hiç merak etmez.

"Aşamalı" Burada Gerçekte Ne Anlama Gelir

Bu bağlamda aşamalı kelimesinin iki anlamı vardır. Birincisi: aşamalı iyileştirme — yükleme 2012'den kalma bir tarayıcıda sade bir <input type="file"> POST olarak çalışır; JavaScript mevcut olduğunda sürükle-bırak, parçalama ve yeniden deneme özellikleri devreye girer. İkincisi: aşamalı açıklama — kullanıcı arayüzü karmaşıklığı yalnızca gerektiğinde gösterir; yükleme sırasında yüzde gösterir, yeniden deneme ayrıntılarını ise yalnızca hata durumunda açar. Her iki anlam aynı ilkeye işaret eder: kullanıcı hiçbir zaman çıkmaza girmemeli ve bilgi almadan beklememeli.

Kaçınılması gereken başarısızlık biçimi "kader döngüsü" dur — ilerleme, tahmini süre veya bir şeylerin yanlış gittiği konusunda hiçbir ipucu vermeyen genel bir yükleme animasyonu. Kullanıcılar güvenmedikleri yüklemeleri iptal eder.

Tarayıcıyla Çatışmayan Sürükle-Bırak

HTML5 sürükle-bırak API'si hatalarıyla ünlüdür. Bunu tolere edilebilir kılan birkaç kural:

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 üzerinde preventDefault çağrılmazsa bırakma hedefi bırakmayı kabul etmez. Klasörleri webkitGetAsEntry() ile kabul etmeniz gerekiyorsa files yerine e.dataTransfer.items kullanın — Chrome ve Firefox'ta dizin içeriklerini özyinelemeli olarak yakalamanın tek yolu budur.

Geri dönüşü de kullanılabilir yapın: biçimlendirilmiş bir <input type="file" multiple> saran görünür bir <label>, klavye ve ekran okuyucu navigasyonu dahil %100 kullanıcıda çalışır.

Kullanıcıların İnandığı İlerleme Göstergeleri

İlerleme çubukları üç nedenden zıplar: eşitsiz parça boyutları, TCP yavaş başlangıcı ve ağ yığınındaki tamponlama. Bunları 2 saniyelik takip eden ortalamayla düzeltin:

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);
}

Tahmini süreyi (toplamBayt - yüklenenBayt) / throughput() olarak hesaplayın, gösterimi en az 5 saniyeyle sınırlayın ve insan diline çevirin: "yaklaşık 2 dakika", "124,3 saniye" değil. Hem yüzde hem de bayt sayacı gösterin ("2,1 GB'ın 340 MB'ı") — bir şeyler yanlış hissettirdiğinde kullanıcılar ikisini çapraz kontrol eder.

Eyleme Dönüştürülebilir Kurtarmalı Hata Durumları

Genel "yükleme başarısız" mesajları güveni yıkar. Hataları beş gruba ayırın ve her birini ayrı biçimde gösterin:

  • Ağ kesintisi (çevrimdışı olayı, TCP sıfırlama): Otomatik yeniden denemeyle "Yeniden bağlanıyor..."
  • Sunucu 5xx: Manuel yeniden deneme düğmesiyle "Sunucu hatası, 5 saniye içinde yeniden denenecek"
  • Sunucu 4xx (413 çok büyük, 415 hatalı tür): Dosya değiştirme seçeneğiyle "Dosya reddedildi: çok büyük"
  • Kimlik doğrulama süresi doldu (401, 403): "Oturum süresi doldu, devam etmek için giriş yapın"
  • İstemci çökmesi (JS hatası, tarayıcı sekmeyi kapattı): Yeniden yükleme sırasında IndexedDB'den kurtarma

Mesajla birlikte çözecek tek eylemi sunun. Kullanıcı çevrimdışıysa navigator.onLine ve online olayıyla izlenen çevrimiçi/çevrimdışı durumunu gösterin.

Fetch Akışlarıyla Bayt Takibi

XMLHttpRequest.upload.onprogress geleneksel olarak yükleme ilerlemesini takip etmek için kullanılmıştır; ancak HTTP/3'te güvenilmez davranır ve gönderme arabelleğindeki kuyruğa alınmış baytları kaçırır. Modern yaklaşım, baytlar üretildikçe saymak için ReadableStream kullanır:

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);
      }
    }
  });
}

Akışı duplex: 'half' ile fetch'e body olarak iletin. Safari'nin istek akışları desteği 17.4 sürümünde geldi; öncesinde XMLHttpRequest'e geri düşün. Bu, ağ yığınına teslim edilen gerçek baytlara bağlı milisaniye hassasiyetinde ilerleme sağlar.

Duraklat, Devam Et ve İptal

Bir dakikadan uzun süren her şeyde kullanıcılar duraklat düğmesi bekler. Parçalı yüklemelerde duraklat yalnızca "yeni parça göndermeyi durdur" anlamına gelir; devam et, iş kuyruğunun kaldığı yerden başlar. İptal AbortController kullanır:

const ctrl = new AbortController();
cancelButton.onclick = () => ctrl.abort();
await fetch(url, { method: 'PUT', body: blob, signal: ctrl.signal });

İptal sonrası temizlik yapın: depolama sızdırmaması için sunucudaki yükleme oturumunu DELETE ile silin, IndexedDB girişini temizleyin, başlangıç durumuna dönün. Duraklat durumu korumalı; iptal ise yok etmeli. Aradaki farkı kullanıcı arayüzünde görünür kılın.

Sekme Yenilemelerinden Sağ Çıkmak

Her başarılı parçanın ardından yükleme durumunu kalıcı hale getirin:

await idb.put('uploads', {
  sessionId, fileFingerprint, fileName, fileSize,
  completedChunks: [...done], updatedAt: Date.now()
}, sessionId);

Parmak izi, dosyanın ilk 1 MB'ının SHA-256'sı ile boyut ve lastModified değerinin birleşimidir — kullanıcı yeniden yüklemeden sonra dosyayı tekrar seçtiğinde onu yeniden tanımlamaya yeterlidir. Sayfa yüklenirken IndexedDB'yi bir saatten eski olmayan oturumlar için kontrol edin ve devam ettirme teklif edin: "12 dakika önce başlattığınız yükleme devam ediyor. Kaldığınız yerden devam edilsin mi?" Onay almadan otomatik devam ettirmeyin — kullanıcılar bazen tam olarak iptal etmek için yeniler.

Erişilebilir ve Klavye Dostu Etkileşimler

Yalnızca fare sürüklemelerine yanıt veren bir bırakma alanı, ekran okuyucu ve klavye kullanıcıları için başarısızdır. Şunları ekleyin:

  • Bırakma alanına role="button" ve tabindex="0"
  • Dosya girişine tıklayan Enter/Space tuş işleyicisi
  • İlerleme bölgesine aria-live="polite" — ekran okuyucular dönüm noktalarını duyurur
  • Yalnızca fareyle üzerine gelindiğinde değil, görünür odak stilleri
  • Açık etiketler — "Dosya yükle", "Gözat"tan iyidir; çıplak bir ikondan ise çok daha iyidir

Klavye testi hızlıdır: farenizi 10 dakika çıkarın ve bir yüklemeyi tamamlamaya çalışın. Yapamazsanız, kullanıcılarınızın bir kısmı da yapamaz.

HexaTransfer'in yükleyicisi tam olarak bu aşamalı deseni kullanır — düz form geri dönüşü, sürükle-bırak iyileştirmesi, fetch akışı, IndexedDB destekli devam ve spesifik hata kurtarma. hexatransfer.com'da deneyin — ücretsiz, hesap gerekmez, maksimum 10 GB.

Kullanıcıların Gerçekten Fark Ettiği Ayrıntılar

Unutulabilir yükleyicileri harika olanlardan ayıran cila küçük anlarda yaşar: dosyanın yakalandığını doğrulayan bir bırakma animasyonu, zıplamak yerine düzgün dolduran bir ilerleme çubuğu, çılgınca değişmek yerine zamanla daha isabetli hale gelen tahmini süre, sıradaki adımı söyleyen spesifik hata mesajları, kazara yenileme sonrası devam etme teklifi, paylaşım bağlantısını kopyalamak için yeterince uzun süren tamamlanma durumu ve yüklemeyi gerçekten anında durduran iptal davranışı. Bunların her biri birkaç satır kod. Hepsini gönderdiğinizde yükleyiciniz, varsayılan <input type="file"> uygulamasından bir mertebe daha iyi hissettir.

Uçtan uca şifreleme ile büyük dosyaları güvenle gönderin

Uçtan uca şifreleme ile 10 GB'a kadar dosya ücretsiz aktarın. Hesap gerekmez. Dosyalarınız yüklenmeden önce tarayıcınızda şifrelenir — başka kimse okuyamaz.

Dosya gönder