File API, Blob, FileReader, загрузка файлов

↑ 7.4 Browser API · ← Предыдущая · → Следующая

Желательно~3 мин чтенияУровень: senior

Зачем это на собесе

Загрузка и скачивание файлов — типовая задача; спрашивают Blob, прогресс, большие файлы.

Основные объекты

  • File — файл из <input type="file"> или drag-and-drop (наследует Blob, имя, размер, тип);
  • Blob — неизменяемые бинарные данные;
  • FileReader — асинхронное чтение (readAsText, readAsDataURL, readAsArrayBuffer);
  • URL.createObjectURL(blob) — временная ссылка для превью или скачивания (не забыть revokeObjectURL).

Загрузка

function onPick(e: Event) {
  const file = (e.target as HTMLInputElement).files?.[0]
  if (!file) return
  if (file.size > 10 * 1024 * 1024) return showError('Файл больше 10 МБ')
  preview.value = URL.createObjectURL(file)
  upload(file)
}
 
async function upload(file: File) {
  const fd = new FormData()
  fd.append('file', file)
  await fetch('/api/files', { method: 'POST', body: fd })   // Content-Type выставится сам
}

Прогресс: XMLHttpRequest.upload.onprogress или axios onUploadProgress (fetch не отдаёт прогресс загрузки).

Скачивание

async function download(url: string, name: string) {
  const blob = await fetch(url).then(r => r.blob())
  const a = document.createElement('a')
  a.href = URL.createObjectURL(blob)
  a.download = name
  a.click()
  URL.revokeObjectURL(a.href)
}

Большие файлы

  • чтение по частям: file.slice(start, end);
  • chunked upload с возобновлением (tus, S3 multipart): куски параллельно, повтор только упавших;
  • presigned URL: загрузка напрямую в хранилище, минуя бэкенд;
  • стримы: file.stream(), ReadableStream.

Drag & Drop

el.addEventListener('dragover', e => e.preventDefault())
el.addEventListener('drop', e => { e.preventDefault(); handle([...(e.dataTransfer?.files ?? [])]) })

Безопасность

Проверка типа и размера на клиенте — только удобство; окончательная валидация (MIME по содержимому, антивирус) на сервере.

Вопросы с ответами