Существует множество различных вариантов хранения данных в браузере. Какой из них лучше всего подходит для ваших нужд?
В дороге интернет-соединение может быть нестабильным или отсутствовать вовсе, поэтому поддержка работы в автономном режиме и надежная производительность являются распространенными функциями прогрессивных веб-приложений . Даже в идеальных беспроводных средах разумное использование кэширования и других методов хранения может существенно улучшить пользовательский опыт. Существует несколько способов кэширования статических ресурсов приложения (HTML, JavaScript, CSS, изображения и т. д.) и данных (пользовательские данные, новостные статьи и т. д.). Но какое решение лучше всего? Сколько данных можно хранить? Как предотвратить их вытеснение?
Что мне следует использовать?
Вот общие рекомендации по хранению ресурсов:
- Для получения сетевых ресурсов, необходимых для загрузки вашего приложения, используйте API хранилища кэша (часть сервисных воркеров ).
- Для файлового контента используйте файловую систему Origin Private File System (OPFS) .
- Для других данных используйте IndexedDB (с оберткой из промисов ).
IndexedDB, OPFS и API Cache Storage поддерживаются всеми современными браузерами. Они асинхронны и не блокируют основной поток (но существует также синхронный вариант OPFS, доступный исключительно в веб-воркерах). К ним можно получить доступ из объекта window , веб-воркеров и сервис-воркеров, что позволяет использовать их в любом месте кода.
А как насчет других механизмов хранения?
В браузере доступно несколько других механизмов хранения данных, но их возможности ограничены, и они могут вызывать значительные проблемы с производительностью.
SessionStorage — это хранилище, привязанное к конкретной вкладке и ограниченное временем жизни вкладки. Оно может быть полезно для хранения небольших объемов информации, специфичной для сессии, например, ключа IndexedDB. Использовать его следует с осторожностью, поскольку оно синхронно и блокирует основной поток. Его размер ограничен примерно 5 МБ, и оно может содержать только строки. Поскольку оно привязано к конкретной вкладке, оно недоступно для веб-воркеров или сервис-воркеров.
Следует избегать использования LocalStorage , поскольку он работает синхронно и блокирует основной поток. Его размер ограничен примерно 5 МБ, и он может содержать только строки. LocalStorage недоступен для веб-воркеров или сервис-воркеров.
Файлы cookie имеют свои преимущества, но не должны использоваться для хранения данных. Файлы cookie отправляются с каждым HTTP-запросом, поэтому хранение чего-либо, кроме небольшого объема данных, значительно увеличит размер каждого веб-запроса. Они синхронны и недоступны для веб-воркеров. Как и LocalStorage и SessionStorage, файлы cookie ограничены только строками.
API доступа к файловой системе был разработан для того, чтобы пользователи могли читать и редактировать файлы в своей локальной файловой системе. Пользователь должен предоставить разрешение, прежде чем страница сможет читать или записывать данные в любой локальный файл, и разрешения не сохраняются между сессиями, если только дескриптор файла не кэширован в IndexedDB. API доступа к файловой системе лучше всего подходит для таких сценариев использования, как редакторы, где необходимо открыть файл, изменить его, а затем, возможно, сохранить изменения обратно в файл.
API файловой системы и API FileWriter предоставляют методы для чтения и записи файлов в изолированную файловую систему. Хотя это асинхронный процесс, его не рекомендуется использовать, поскольку он доступен только в браузерах на основе Chromium .
Сколько я могу хранить?
Короче говоря, очень много , как минимум пара сотен мегабайт, а потенциально сотни гигабайт и более. Реализации браузеров различаются, но объем доступного хранилища обычно зависит от объема памяти, доступной на устройстве.
- Chrome позволяет браузеру использовать до 80% всего дискового пространства. Источник может использовать до 60% всего дискового пространства. Вы можете использовать API StorageManager для определения максимально доступной квоты. В других браузерах на основе Chromium могут быть другие параметры.
- В режиме инкогнито Chrome уменьшает объем памяти, доступный для использования источником, примерно до 5% от общего дискового пространства.
- Если в Chrome включена опция «Очищать файлы cookie и данные сайтов при закрытии всех окон», объем используемого хранилища значительно сокращается и составляет максимум около 300 МБ.
- Firefox позволяет браузеру использовать до 50% свободного дискового пространства. Группа доменов верхнего уровня с расширением eTLD+1 (например,
example.com,www.example.comиfoo.bar.example.com) может использовать до 2 ГБ . Вы можете использовать API StorageManager , чтобы определить, сколько места еще доступно. - Safari (как на компьютере, так и на мобильном устройстве) ограничивает объем данных примерно до 1 ГБ. При достижении лимита Safari предложит пользователю увеличить его на 200 МБ с шагом в 200 МБ. Мне не удалось найти никакой официальной документации по этому поводу.
- Если PWA добавляется на главный экран мобильного Safari, создаётся новый контейнер для хранения данных, и данные между PWA и мобильным Safari не передаются. После того, как квота для установленного PWA исчерпана, запросить дополнительное хранилище, по всей видимости, невозможно.
Раньше, если сайт превышал определённый порог объёма хранимых данных, браузер запрашивал у пользователя разрешение на использование дополнительных данных. Например, если источник использовал более 50 МБ, браузер запрашивал разрешение на хранение до 100 МБ, а затем запрашивал разрешение ещё раз с шагом в 50 МБ.
Сегодня большинство современных браузеров не запрашивают у пользователя разрешение и позволяют сайту использовать выделенную квоту. Исключением, по-видимому, является Safari, который запрашивает разрешение на увеличение выделенной квоты при превышении квоты хранилища. Если источник попытается использовать больше выделенной квоты, дальнейшие попытки записи данных завершатся неудачей.
Как проверить, сколько места в хранилище доступно?
Во многих браузерах можно использовать API StorageManager для определения объема доступного исходному серверу хранилища и объема используемого им хранилища. Он сообщает общее количество байтов, используемых IndexedDB и API кэширования, и позволяет рассчитать приблизительное оставшееся доступное пространство для хранения.
if (navigator.storage && navigator.storage.estimate) {
const quota = await navigator.storage.estimate();
// quota.usage -> Number of bytes used.
// quota.quota -> Maximum number of bytes available.
const percentageUsed = (quota.usage / quota.quota) * 100;
console.log(`You've used ${percentageUsed}% of the available storage.`);
const remaining = quota.quota - quota.usage;
console.log(`You can write up to ${remaining} more bytes.`);
}
Необходимо выявлять ошибки превышения квоты (см. ниже). В некоторых случаях доступная квота может превышать фактический объем доступного хранилища.
Осмотреть
В процессе разработки вы можете использовать инструменты разработчика в браузере, чтобы проверить различные типы хранилища и удалить все сохраненные данные.
В Chrome 88 добавлена новая функция, позволяющая переопределять квоту хранилища сайта в панели «Хранилище». Эта функция дает возможность имитировать работу различных устройств и тестировать поведение ваших приложений в условиях низкой доступности диска. Перейдите в раздел «Приложения» , затем «Хранилище» , установите флажок «Имитировать пользовательскую квоту хранилища» и введите любое допустимое число для имитации квоты хранилища.
В процессе работы над этим руководством я написал простой инструмент , позволяющий быстро использовать как можно больше места для хранения данных. Это быстрый способ поэкспериментировать с различными механизмами хранения и посмотреть, что произойдет, когда вы израсходуете всю свою квоту.
Как поступить в случае превышения квоты?
Что делать при превышении квоты? Самое важное — всегда перехватывайте и обрабатывайте ошибки записи, будь то QuotaExceededError или что-то другое. Затем, в зависимости от дизайна вашего приложения, решите, как с этим справиться. Например, удалите контент, к которому давно не обращались, удалите данные по размеру или предоставьте пользователям возможность выбирать, что они хотят удалить.
Как IndexedDB, так и API кэширования выдают DOMError с именем QuotaExceededError , когда превышена доступная квота.
Индексированная база данных
Если источник превысил свою квоту, попытки записи в IndexedDB завершатся неудачей. Будет вызван обработчик onabort() транзакции, передающий событие. Событие будет содержать исключение DOMException в свойстве error. Проверка name ошибки вернет QuotaExceededError .
const transaction = idb.transaction(['entries'], 'readwrite');
transaction.onabort = function(event) {
const error = event.target.error; // DOMException
if (error.name == 'QuotaExceededError') {
// Fallback code goes here
}
};
API кэширования
Если источник превысил свою квоту, попытки записи в API кэша будут отклонены с ошибкой DOMException QuotaExceededError .
try {
const cache = await caches.open('my-cache');
await cache.add(new Request('/sample1.jpg'));
} catch (err) {
if (error.name === 'QuotaExceededError') {
// Fallback code goes here
}
}
Как происходит выселение?
Веб-хранилище делится на две категории: «Наиболее вероятное использование» и «Постоянное». «Наиболее вероятное использование» означает, что хранилище может быть очищено браузером без прерывания работы пользователя, но оно менее надежно для долгосрочных или критически важных данных. Постоянное хранилище не очищается автоматически при низком уровне памяти. Пользователю необходимо очистить это хранилище вручную (через настройки браузера).
По умолчанию данные сайта (включая IndexedDB, Cache API и т. д.) попадают в категорию «максимальные усилия», что означает, что, если сайт не запросил постоянное хранилище , браузер может удалить данные сайта по своему усмотрению, например, когда в памяти устройства мало места.
Политика выселения, основанная на принципе максимальных усилий, следующая:
- Браузеры на основе Chromium начнут удалять данные, когда в браузере закончится место, очищая все данные сайтов сначала с наименее часто используемого источника, затем со следующего, пока браузер не перестанет превышать лимит.
- Firefox начнет удалять данные, когда доступное дисковое пространство будет заполнено, очищая данные всех сайтов сначала с наименее часто используемого источника, затем со следующего, пока браузер не перестанет превышать лимит.
- Ранее Safari не удалял данные, но недавно ввел новое семидневное ограничение на объем записываемого хранилища (см. ниже).
Начиная с iOS и iPadOS 13.4 и Safari 13.1 на macOS, действует семидневное ограничение на объем памяти, доступной для записи скриптов, включая IndexedDB, регистрацию сервис-воркеров и API кэширования. Это означает, что Safari удалит весь контент из кэша через семь дней после начала использования, если пользователь не взаимодействует с сайтом. Эта политика удаления не распространяется на установленные PWA , добавленные на главный экран. Подробную информацию см. в разделе «Полная блокировка сторонних файлов cookie и многое другое» в блоге WebKit.
Контейнеры для хранения
Основная идея API Storage Buckets заключается в предоставлении сайтам возможности создавать несколько хранилищ, из которых браузер может удалять независимо от других. Это позволяет разработчикам задавать приоритет удаления, чтобы гарантировать, что наиболее ценные данные не будут удалены.
Бонус: Зачем использовать обертку для IndexedDB?
IndexedDB — это низкоуровневый API, требующий значительной предварительной настройки, что может быть особенно проблематично при хранении данных низкой сложности. В отличие от большинства современных API, основанных на промисах, он основан на событиях. Обертки для промисов, такие как idb для IndexedDB, скрывают некоторые мощные функции, но, что более важно, скрывают сложный механизм (например, транзакции, версионирование схемы), который поставляется с библиотекой IndexedDB.
Бонус: SQLite Wasm
После того, как Web SQL был признан устаревшим и удален из Chrome, Google совместно с разработчиками популярной базы данных SQLite предложили замену Web SQL, основанную на SQLite. Подробнее о том, как его использовать, читайте в статье «SQLite Wasm в браузере с поддержкой Origin Private File System» .
Заключение
Прошли времена ограниченного объема хранилища и необходимости постоянно запрашивать у пользователя все больше и больше данных. Сайты могут хранить практически все необходимые для работы ресурсы и данные. Используя API StorageManager, вы можете определить, сколько данных вам доступно и сколько вы уже использовали. А благодаря постоянному хранилищу , если пользователь его не удалит, вы можете защитить его от вытеснения.
Дополнительные ресурсы
Спасибо
Особая благодарность Джарриду Гудману, Филу Уолтону, Эйдзи Китамуре, Даниэлю Мерфи, Дарвину Хуангу, Джошу Беллу, Марийну Круиссельбринку и Виктору Костану за рецензирование этого руководства. Спасибо Эйдзи Китамуре, Адди Османи и Марку Коэну, написавшим оригинальные статьи, на которых основано это руководство. Эйдзи разработал полезный инструмент под названием Browser Storage Abuser , который помог проверить текущее поведение браузера. Он позволяет хранить как можно больше данных и видеть ограничения хранилища в вашем браузере. Спасибо Франсуа Бофору, который изучил Safari, чтобы выяснить его ограничения хранилища, и Томасу Штайнеру за добавление информации об исходной частной файловой системе, хранилищах данных, SQLite Wasm и общем обновлении контента в 2024 году.