Вопрос проверяет понимание работы потоков данных (streams) в браузере при обработке больших ответов от сервера и знание способов избежать переполнения памяти.
Когда вы используете fetch для получения данных, браузер по умолчанию буферизует весь ответ тела (body) в памяти. Это удобно для небольших JSON-ответов или изображений, но становится проблемой для больших файлов, таких как видео, архивы или дампы баз данных.
Методы response.json(), response.text() или response.blob() читают всё тело ответа и преобразуют его в соответствующий формат, полностью сохраняя результат в памяти JavaScript. Если файл размером 2 ГБ, то перед обработкой в вашем коде браузер должен выделить как минимум 2 ГБ оперативной памяти под этот буфер. Это может превысить лимиты памяти, доступные для вкладки браузера, и привести к ошибке "out of memory" или просто к зависанию.
Современный API fetch возвращает объект Response, у которого свойство body является ReadableStream. Этот поток позволяет читать данные чанками (кусками) по мере их поступления с сервера. Вы можете обрабатывать каждый чанк и сразу освобождать память, не дожидаясь загрузки всего файла.
Вот как можно скачать большой файл и сохранить его на диск пользователя с помощью потоков, избегая переполнения памяти:
async function downloadLargeFile(url, filename) {
// Запрашиваем ресурс
const response = await fetch(url);
// Получаем поток из тела ответа
const readableStream = response.body;
// Создаём поток для записи в файл через File System Access API
// (в реальном коде нужна проверка поддержки браузером)
const fileStream = await createWritableStream(filename);
// Потоково копируем данные из ответа в файл
await readableStream.pipeTo(fileStream);
console.log('Файл сохранён!');
}
// Упрощённая функция для демонстрации (в реальности используйте showSaveFilePicker)
async function createWritableStream(filename) {
// Для примера: создаём объект Blob и ссылку для скачивания
// Это не потоковое сохранение на диск, а демонстрация обработки чанков.
const chunks = [];
const writer = {
write(chunk) {
// Обрабатываем каждый чанк данных
chunks.push(chunk);
// Здесь можно, например, отправлять чанк в WebSocket
// или вычислять хэш-сумму на лету
console.log(`Получено ${chunk.byteLength} байт`);
},
close() {
// В конце собираем файл (для примера, в реальности так делать не нужно)
const blob = new Blob(chunks);
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = filename;
link.click();
}
};
return writer;
}
Вывод: Используйте Streams API через response.body при работе с потенциально большими ответами от сервера, чтобы обрабатывать данные по частям и избегать переполнения памяти. Это критически важно для создания отзывчивых веб-приложений, работающих с большими объёмами данных.