Логотип YeaHub

База вопросов

Собеседования

Тренажёр

База ресурсов

Обучение

Навыки

Войти

Выбери, каким будет IT завтра — вместе c нами!

YeaHub — это полностью открытый проект, призванный объединить и улучшить IT-сферу. Наш исходный код доступен для просмотра на GitHub. Дизайн проекта также открыт для ознакомления в Figma.

© 2026 YeaHub

Документы

Медиа

Назад
Вопрос про JavaScript: fetch, streams API, blob, service worker, content-disposition

Какие способы существуют для скачивания больших файлов в браузере без загрузки в память?

Вопрос проверяет знание методов обработки больших файлов в браузере, позволяющих избежать перегрузки памяти, что критично для веб-приложений, работающих с объёмными данными.

Короткий ответ

Основной способ — использование Streams API вместе с Fetch API для поточной обработки данных. Это позволяет читать и обрабатывать файл по частям, не загружая его целиком в память. Также можно использовать атрибут `download` у ссылки или заголовок `Content-Disposition: attachment` для прямого скачивания файла сервером. Для очень больших файлов иногда применяют Service Workers для кэширования частей файла.

Длинный ответ

При скачивании больших файлов в браузере ключевая задача — избежать загрузки всего файла в оперативную память (RAM) пользователя, что может привести к падению производительности или краху вкладки. Традиционный подход с XMLHttpRequest или простым fetch() загружает весь ответ в память как Blob или строку, что неприемлемо для гигабайтных файлов. Современные API предоставляют механизмы для потоковой обработки.

1. Использование Fetch API с Streams

Fetch API может возвращать ответ как читаемый поток (ReadableStream). Вы можете обрабатывать данные по мере их поступления с сервера, например, сразу записывать их на диск пользователя (если браузер поддерживает File System Access API) или выполнять поточную обработку.

async function downloadLargeFile(url) {
  const response = await fetch(url);
  const reader = response.body.getReader();
  const chunks = [];

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    // value — это Uint8Array (чанк данных)
    chunks.push(value);
    // Здесь можно отправлять чанки дальше, например, в другой поток
  }
  // Объединять чанки в памяти не стоит для очень больших файлов
  // Лучше использовать WritableStream для записи на диск
}

2. Прямое скачивание через ссылку или iframe

Самый простой и безопасный для памяти способ — заставить браузер обрабатывать файл как загрузку. Это можно сделать, создав ссылку с атрибутом download или используя iframe. Файл сохраняется напрямую в папку загрузок, минуя память JavaScript.

// Способ 1: Создание временной ссылки
const link = document.createElement('a');
link.href = 'https://example.com/large-file.zip';
link.download = 'file.zip';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

// Способ 2: Использование iframe
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = 'https://example.com/large-file.zip';
document.body.appendChild(iframe);
// Файл начнёт скачиваться

Этот метод работает, если сервер отправляет правильный заголовок Content-Disposition: attachment.

3. File System Access API (экспериментальный)

В современных браузерах (Chrome, Edge) можно использовать File System Access API для создания файла на диске пользователя и потоковой записи в него данных через Fetch. Это позволяет скачивать файлы любого размера, записывая их на диск по частям.

async function saveLargeFileStream(url, fileName) {
  const response = await fetch(url);
  const fileHandle = await window.showSaveFilePicker({
    suggestedName: fileName
  });
  const writableStream = await fileHandle.createWritable();
  await response.body.pipeTo(writableStream); // Потоковая передача!
  console.log('Файл сохранён на диск.');
}

4. Разбиение на части (chunked download)

Если сервер поддерживает диапазоны байтов (заголовок Accept-Ranges: bytes), можно скачивать файл по частям с помощью заголовка Range. Каждую часть можно обрабатывать отдельно, а затем объединить на клиенте (например, с помощью File System Access API).

async function downloadInChunks(url, chunkSize = 1024 * 1024) {
  // Сначала узнаем размер файла
  const headResponse = await fetch(url, { method: 'HEAD' });
  const totalSize = parseInt(headResponse.headers.get('Content-Length'), 10);
  
  for (let start = 0; start < totalSize; start += chunkSize) {
    const end = Math.min(start + chunkSize - 1, totalSize - 1);
    const response = await fetch(url, {
      headers: { 'Range': `bytes=${start}-${end}` }
    });
    const chunk = await response.arrayBuffer();
    // Обработка каждого чанка
  }
}

Вывод: Для скачивания больших файлов без загрузки в память предпочтительно использовать потоковые API (Fetch + Streams) в сочетании с File System Access API для прямой записи на диск. Если требуется максимальная совместимость, подойдёт метод с созданием ссылки или iframe, который перекладывает задачу скачивания на браузер.

Уровень

  • Рейтинг:

    3

  • Сложность:

    5

Навыки

  • JavaScript

    JavaScript

  • HTML

    HTML

Ключевые слова

#fetch

#streams API

#blob

#service worker

#content-disposition

Подпишись на React Developer в телеграм