Потоковая передача сгенерированного на стороне клиента ответа в виде загрузки без сервис-воркера

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

Обычным методом было бы создать Blob, а затем создать для него URL-адрес объекта:

const blob = new Blob([chunks], {type: 'application/example'});
linkEl.href = URL.createObjectUrl(blob);

Это работает, но не очень эффективно, поскольку может быстро исчерпать всю доступную память, поскольку полученный файл должен оставаться в памяти.

Лучшим способом была бы потоковая передача. Что-то вроде этого:

const outputStream = new WritableStream();
linkEl.href = URL.createObjectUrl(outputStream);
while (let chunk = await getChunk()) {
  outputStream.write();
}
outputStream.end();

Есть ли прямой способ сделать это сегодня?

Единственный метод, который я видел для потоковой передачи, - это использование Service Worker. К сожалению, во многих ситуациях Service Worker недоступен. Режимы конфиденциальности могут обходить всех сервисных работников. Жесткое обновление страницы отключает их. Открытие инструментов браузера может сбросить состояние сервис-воркера. Рабочий может быть отключен в любой момент, и попытки поддержать его с помощью обмена сообщениями не гарантируются. Все эти хаки были реализованы в отличном проекте здесь: https://github.com/jimmywarting/StreamSaver.js. Но, в конце концов, это ненадежно из-за ограничений браузера.

Существует ли подходящий API для потоковой передачи "загрузки" на стороне клиента без использования сервис-воркера?

1 ответ

Решение

Одно определяется... Родная файловая система.

Это все еще ранний черновик, и только Chrome начал его реализовывать, но вы уже можете попробовать его после включения chrome://flags/#native-file-system-api флаг.

Вас особенно заинтересует интерфейс FileSystemWritableFileStream, который позволит производить запись на диск после того, как пользователь выберет, где вы можете возиться с его данными;-)

Неактивный код, поскольку "В изолированных документах не может отображаться средство выбора файлов". ...

onclick = async () => {

if( !("chooseFileSystemEntries" in self) ) {
  throw new Error( "unsupported browser" );
}

const handle = await chooseFileSystemEntries( { type:'save-file' } );
const filestream = await handle.createWritable();
const writer = await filestream.getWriter();
// here we have a WritableStream, with direct access to the user's disk
await writer.write( "hello" );
await writer.write( " world" );
writer.close();

};

Вот живой plnkr, который нужно запускать в оконном режиме.

Другие вопросы по тегам