Веб-платформа всё чаще предлагает разработчикам инструменты, необходимые для создания оптимизированных высокопроизводительных веб-приложений. В частности, WebAssembly (Wasm) открыл путь к быстрым и мощным веб-приложениям, а такие технологии, как Emscripten, теперь позволяют разработчикам повторно использовать проверенный и проверенный код в вебе. Чтобы в полной мере раскрыть этот потенциал, разработчикам необходимо обладать такими же возможностями и гибкостью в области хранения данных.
Именно здесь на помощь приходит Storage Foundation API. Storage Foundation API — это новый быстрый и нестандартный API для хранения данных, который открывает новые и востребованные возможности использования в вебе, такие как реализация производительных баз данных и эффективное управление большими временными файлами. С помощью этого нового интерфейса разработчики могут «привнести собственное хранилище» в веб, сокращая разрыв в функциональности между веб- и платформенно-специфичным кодом.
API Storage Foundation разработан таким образом, чтобы напоминать очень простую файловую систему, что обеспечивает разработчикам гибкость, предоставляя универсальные, простые и производительные примитивы, на основе которых они могут создавать компоненты более высокого уровня. Приложения могут использовать наиболее подходящий инструмент для своих задач, находя оптимальный баланс между удобством использования, производительностью и надёжностью.
Зачем Интернету нужен еще один API для хранения данных?
Веб-платформа предлагает разработчикам ряд вариантов хранения данных, каждый из которых создан с учетом конкретных вариантов использования.
- Некоторые из этих вариантов явно не пересекаются с этим предложением, поскольку они позволяют хранить только очень небольшие объемы данных, например файлы cookie или API веб-хранилища, состоящий из механизмов
sessionStorage
иlocalStorage
. - Другие варианты уже устарели по разным причинам, например API файлов и каталогов или WebSQL .
- API доступа к файловой системе имеет схожую структуру, но предназначен для взаимодействия с файловой системой клиента и предоставления доступа к данным, которые могут находиться за пределами владения источника или даже браузера. Эта иная направленность влечет за собой более строгие требования к безопасности и более высокие затраты на производительность.
- API IndexedDB можно использовать в качестве бэкенда для некоторых сценариев использования Storage Foundation API. Например, Emscripten включает IDBFS — персистентную файловую систему на основе IndexedDB. Однако, поскольку IndexedDB по сути является хранилищем типа «ключ-значение», его производительность существенно ограничена. Более того, прямой доступ к подразделам файла в IndexedDB ещё сложнее и медленнее.
- Наконец, интерфейс CacheStorage широко поддерживается и настроен для хранения больших объемов данных, таких как ресурсы веб-приложений, но значения неизменяемы.
Storage Foundation API — это попытка закрыть все пробелы предыдущих вариантов хранения, обеспечивая производительное хранение изменяемых больших файлов, определенных в источнике приложения.
Предлагаемые варианты использования API Storage Foundation
Примеры сайтов, которые могут использовать этот API:
- Приложения для продуктивной работы или творчества, работающие с большими объёмами видео-, аудио- или графических данных. Такие приложения могут выгружать сегменты на диск, а не хранить их в памяти.
- Приложения, которые используют постоянную файловую систему, доступную из Wasm, и которым требуется большая производительность, чем может гарантировать IDBFS.
Что такое API Storage Foundation?
API состоит из двух основных частей:
- Вызовы файловой системы , которые обеспечивают базовую функциональность для взаимодействия с файлами и путями к файлам.
- Дескрипторы файлов , которые обеспечивают доступ для чтения и записи к существующему файлу.
Вызовы файловой системы
API Storage Foundation представляет новый объект storageFoundation
, который находится на объекте window
и включает в себя ряд функций:
-
storageFoundation.open(name)
: открывает файл с заданным именем, если он существует, или создаёт новый файл в противном случае. Возвращает обещание, которое разрешается с открытым файлом.
-
storageFoundation.delete(name)
: удаляет файл с указанным именем. Возвращает обещание, которое выполняется после удаления файла. -
storageFoundation.rename(oldName, newName)
: атомарно переименовывает файл из старого имени в новое. Возвращает обещание, которое разрешается при переименовании файла. -
storageFoundation.getAll()
: возвращает обещание, которое разрешается с помощью массива всех существующих имен файлов. -
storageFoundation.requestCapacity(requestedCapacity)
: запрашивает новую ёмкость (в байтах) для использования текущим контекстом выполнения. Возвращает обещание, которое было выполнено с оставшимся доступным объёмом ёмкости.
-
storageFoundation.releaseCapacity(toBeReleasedCapacity)
: освобождает указанное количество байтов из текущего контекста выполнения и возвращает обещание, которое разрешается с оставшейся емкостью. -
storageFoundation.getRemainingCapacity()
: возвращает обещание, которое разрешается с доступной емкостью для текущего контекста выполнения.
Дескрипторы файлов
Работа с файлами происходит посредством следующих функций:
-
NativeIOFile.close()
: закрывает файл и возвращает обещание, которое разрешается после завершения операции. -
NativeIOFile.flush()
: синхронизирует (т.е. очищает) состояние файла в памяти с устройством хранения и возвращает обещание, которое разрешается после завершения операции.
-
NativeIOFile.getLength()
: возвращает обещание, которое разрешается с длиной файла в байтах. -
NativeIOFile.setLength(length)
: устанавливает длину файла в байтах и возвращает обещание, которое выполняется после завершения операции. Если новая длина меньше текущей, байты удаляются, начиная с конца файла. В противном случае файл расширяется нулевыми байтами. NativeIOFile.read(buffer, offset)
: считывает содержимое файла по указанному смещению через буфер, полученный в результате передачи указанного буфера, который затем остаётся отсоединённым. ВозвращаетNativeIOReadResult
с переданным буфером и количеством успешно прочитанных байтов.NativeIOReadResult
— это объект, состоящий из двух записей:-
buffer
:ArrayBufferView
, который является результатом передачи буфера, переданного вread()
. Он имеет тот же тип и длину, что и исходный буфер. -
readBytes
: Количество байтов, успешно считанных вbuffer
. Может быть меньше размера буфера в случае ошибки или если диапазон чтения выходит за пределы конца файла. Значение равно нулю, если диапазон чтения выходит за пределы конца файла.
-
NativeIOFile.write(buffer, offset)
: записывает содержимое указанного буфера в файл по указанному смещению. Буфер передаётся до записи любых данных и поэтому остаётся отсоединённым. ВозвращаетNativeIOWriteResult
с переданным буфером и количеством успешно записанных байтов. Файл будет расширен, если диапазон записи превысит его длину.NativeIOWriteResult
— это объект, состоящий из двух записей:-
buffer
:ArrayBufferView
, являющийся результатом передачи буфера, переданного вwrite()
. Он имеет тот же тип и длину, что и исходный буфер. -
writtenBytes
: Количество байтов, успешно записанных вbuffer
. В случае ошибки это количество может быть меньше размера буфера.
-
Полные примеры
Чтобы сделать изложенные выше концепции более понятными, приведем два полных примера, которые проведут вас по различным этапам жизненного цикла файлов Storage Foundation.
Открытие, написание, чтение, закрытие
// Open a file (creating it if needed).
const file = await storageFoundation.open('test_file');
try {
// Request 100 bytes of capacity for this context.
await storageFoundation.requestCapacity(100);
const writeBuffer = new Uint8Array([64, 65, 66]);
// Write the buffer at offset 0. After this operation, `result.buffer`
// contains the transferred buffer and `result.writtenBytes` is 3,
// the number of bytes written. `writeBuffer` is left detached.
let result = await file.write(writeBuffer, 0);
const readBuffer = new Uint8Array(3);
// Read at offset 1. `result.buffer` contains the transferred buffer,
// `result.readBytes` is 2, the number of bytes read. `readBuffer` is left
// detached.
result = await file.read(readBuffer, 1);
// `Uint8Array(3) [65, 66, 0]`
console.log(result.buffer);
} finally {
file.close();
}
Открытие, листинг, удаление
// Open three different files (creating them if needed).
await storageFoundation.open('sunrise');
await storageFoundation.open('noon');
await storageFoundation.open('sunset');
// List all existing files.
// `["sunset", "sunrise", "noon"]`
await storageFoundation.getAll();
// Delete one of the three files.
await storageFoundation.delete('noon');
// List all remaining existing files.
// `["sunrise", "noon"]`
await storageFoundation.getAll();
Безопасность и разрешения
Команда Chromium разработала и реализовала API Storage Foundation, используя основные принципы, определенные в документе «Управление доступом к мощным функциям веб-платформы» , включая пользовательский контроль, прозрачность и эргономичность.
Следуя той же схеме, что и другие современные API хранилищ в интернете, доступ к API Storage Foundation привязан к источнику, то есть источник может получать доступ только к самостоятельно созданным данным. Доступ к нему также ограничен безопасными контекстами.
Пользовательский контроль
Квота хранилища будет использоваться для распределения доступа к дисковому пространству и предотвращения злоупотреблений. Память, которую вы хотите занять, необходимо предварительно запросить. Как и другие API хранилищ, пользователи могут очистить пространство, занимаемое Storage Foundation API, через браузер.
Полезные ссылки
- Публичный объяснитель
- Ошибка отслеживания Chromium
- Запись ChromeStatus.com
- Компонент Blink:
Blink>Storage>NativeIO
- Обзор TAG
- Намерение создать прототип
- поток WebKit
- ветка Mozilla
Благодарности
API Storage Foundation был разработан и реализован Эмануэлем Кривоем и Ричардом Стотцем . Рецензентами статьи выступили Пит ЛеПейдж и Джо Медли .
Изображение героя предоставлено Маркусом Списке на Unsplash .