Потоковая передача сгенерированного на стороне клиента ответа в виде загрузки без сервис-воркера
Предположим, у меня есть большой файл, который я создаю на стороне клиента, и я хочу, чтобы пользователь мог сохранить его на свой жесткий диск.
Обычным методом было бы создать 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, который нужно запускать в оконном режиме.