- PVSM.RU - https://www.pvsm.ru -
При проектировании веб-приложения чрезвычайно важно выбрать подходящие средства для локального хранения данных. Речь идёт о механизме, который позволит надёжно хранить информацию, будет способствовать снижению объёма данных, передаваемых между серверной и клиентской частями приложения, и при этом не ухудшит скорость реакции приложения на воздействия пользователя. Хорошо продуманная стратегия локального кэширования данных является центральным звеном в разработке мобильных веб-приложений, которые могут работать без подключения к интернету. Современные пользователи всё чаще и чаще относятся к подобным возможностям как к чему-то привычному и ожидаемому.
Сегодня, в переводе 16 части серии материалов, посвящённых всему, что связано с JavaScript, мы поговорим о механизмах хранения данных на стороне клиента, которые могут использоваться в веб-разработке, и о выборе системы хранения данных для конкретного проекта.
Модель данных определяет внутреннюю организацию хранимых данных. Она воздействует на все аспекты устройства веб-приложения, в ней заложены решения, часто компромиссные, от которых зависит эффективность приложения и возможность системы хранения решать поставленные перед ней задачи. Не существует некоего «самого лучшего» подхода к проектированию моделей данных, нет универсальных решений, подходящих для всех приложений. Выбор модели данных основан на особенностях и потребностях конкретного приложения. Рассмотрим несколько основных моделей хранения данных, из которых можно выбрать что-то подходящее для конкретного проекта.
Методы хранения данных, используемые в веб-приложениях, можно проанализировать с точки зрения времени постоянного хранения таких данных.
В наши дни существует немало браузерных API, которые позволяют организовать хранение данных. Мы рассмотрим некоторые из них и сравним их для того, чтобы упростить вам выбор подходящего API.
Для начала, однако, остановимся на нескольких общих вопросах, которые стоит принять к сведению перед выбором конкретной технологии для хранения данных. Конечно, в первую очередь нужно понять то, как ваше приложение будет использоваться, как будет организована его поддержка, как планируется его развивать. При этом, если даже у вас есть чёткие ответы на эти вопросы, вы, в итоге, можете выйти на несколько вариантов систем хранения данных, из которых нужно будет выбрать наиболее подходящий. Вот на что стоит обратить внимание, выбирая систему хранения данных:
В этом разделе мы рассмотрим некоторые из существующих систем хранения данных, доступных веб-разработчикам, и сравним их по описанным выше показателям.
| API | Модель данных | Методика хранения | Поддержка браузерами | Поддержка транзакций | Синхронное или асинхронное |
|---|---|---|---|---|---|
| FileSystem [17] | Последовательность байтов | Устройство | 52% | Нет | Асинхронное |
| LocalStorage [18] | Ключ/значение | Устройство | 93% | Нет | Синхронное |
| SessionStorage [19] | Ключ/значение | Сессия | 93% | Нет | Синхронное |
| Cookie [20] | Структурированные данные | Устройство | 100% | Нет | Синхронное |
| Cache [21] | Ключ/значение | Устройство | 60% | Нет | Асинхронное |
| IndexedDB [22] | Гибридная модель | Устройство | 83% | Да | Асинхронное |
Теперь поговорим подробнее об этих способах хранения данных.

Благодаря использованию API FileSystem [17] веб-приложения могут работать с выделенной областью локальной файловой системы пользователя. Приложение может просматривать содержимое хранилища, создавать файлы, выполнять операции чтения и записи.
Это API состоит из следующих основных частей:
File/Blob, FileList, FileReader
Blob, FileWriter
DirectoryReader, FileEntry/DirectoryEntry, LocalFileSystem
API FileSystem не является стандартным, поэтому его не следует использовать в продакшне, так как оно будет работать не у всех пользователей. Различные реализации этого API могут сильно различаться, кроме того, весьма вероятно то, что в будущем оно может измениться.
Интерфейс filesystem этого API используются для представления файловой системы. Доступ к соответствующим объектам можно получить через свойство filesystem [23]. Некоторые браузеры предлагают дополнительные API для создания файловых систем и управления ими.
Этот интерфейс не даёт веб-странице доступ к файловой системе пользователя. Вместо этого он позволяет работать с чем-то вроде виртуального диска, который находится в «песочнице», создаваемой браузером. Если вашему приложению нужен доступ к файловой системе пользователя, вам понадобится использовать другие механизмы.
Веб-приложение может запросить доступ к виртуальной файловой системе, выполнив вызов window.requestFileSystem():
// Примечание: Здесь используются префиксы Google Chrome 12:
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(type, size, successCallback, opt_errorCallback)
Если вы вызываете requestFileSystem() в первый раз, то для вашего приложения будет создано новое хранилище. Важно помнить, что это — изолированное хранилище, то есть, одно веб-приложение не может работать с хранилищем, созданным другим приложением.
После того, как вы получите доступ к файловой системе, вы сможете выполнять большинство стандартных операций с файлами и директориями.
API FileSystem серьёзно отличается от других подобных систем, используемых веб-приложениями, так как оно нацелено на решение задач хранения данных на клиенте, которые не очень хорошо решаются средствами баз данных. В целом, это — приложения, которые работают с большими фрагментами бинарных данных, либо обмениваются данными с внешними по отношению к браузеру приложениями.
Среди вариантов использования API FileSystem можно отметить следующие:
Вот как обстоят дела с поддержкой API FileSystem браузерами.

Поддержка API FileSystem браузерами

API LocalStorage [18], или локальное хранилище, позволяет работать с объектом Storage [24] объекта Document [25] с учётом принципа одинакового источника. Данные не теряются между сессиями. API LocalStorage похоже на API SessionStorage [26], сессионное хранилище, разница заключается в том, что данные в сессионном хранилище удаляются после того, как сессия страницы завершится, а данные в локальном хранилище хранятся постоянно.
Обратите внимание на то, что данные, размещённые в локальном или в сессионном хранилище привязаны к источнику страницы, который определяется комбинацией протокола, хоста и порта.
Вот сведения о поддержке API LocalStorage различными браузерами.

Поддержка API LocalStorage браузерами
API SessionStorage [19] позволяет работать с объектом Storage [24] сессии. API SessionStorage похоже на API LocalStorage, о котором мы говорили выше. Разница между ними, как уже было сказано, заключается во времени хранения данных, а именно, в случае с SessionStorage данные хранятся столько, сколько длится сессия. Длится она до тех пор, пока открыт браузер, при этом она сохраняется после перезагрузки страницы. Открытие страницы в новой вкладке или окне приведёт к инициированию новой сессии, это отличается от поведения сессионных куки-файлов. При этом, работая и с SessionStorage, и с LocalStorage, надо помнить о том, что данные в таких хранилищах привязаны к источнику страницы.
Вот сведения о поддержке API SessionStorage различными браузерами:

Поддержка API SessionStorage браузерами

Cookie [20] (куки, веб-куки, браузерные куки) — это небольшие фрагменты информации, которые сервер отправляет браузеру. Браузер может их сохранять и отправлять серверу, используя их при формировании запросов к нему. Обычно они используются для идентификации конкретного экземпляра браузера, от которого поступают запросы. Например — для того, чтобы пользователь, после входа в систему, оставался бы в ней. Куки — это нечто вроде системы хранения информации о состоянии сеанса связи для протокола HTTP [27], который рассматривает каждый запрос, даже приходящий из одного и того же браузера, как совершенно независимый от других.
Куки используются для решения трёх основных задач:
В своё время куки применялись как хранилище данных общего назначения. Хотя это и вполне нормальный способ использования куки, особенно, когда они были единственным способом хранения данных на клиенте, в наше время применять их в таком качестве не рекомендуется, отдав предпочтение более современным API. Куки отправляются с каждым запросом, поэтому они могут ухудшить производительность (особенно — на мобильных устройствах).
Существует два вида куки:
Expires), либо неким периодом времени (атрибут Max-Age).
Обратите внимание на то, что конфиденциальную или другую важную информацию не следует хранить в куки-файлах или передавать в HTTP-куки, так как весь механизм работы с куки, по своей сути, небезопасен.
Если говорить о поддержке куки, то их, как вы, вероятно, уже поняли, поддерживают все браузеры.

Интерфейс Cache [21] предоставляет механизм хранения данных для кэшируемых пар объектов Request [28] / Response [29]. Этот интерфейс определён в тех же спецификациях, что и сервис-воркеры, но доступен он не только воркерам. Интерфейс Cache доступен и в области видимости объекта window, его необязательно использовать только с сервис-воркерами.
Некий источник может иметь несколько именованных объектов Cache. Разработчик несёт ответственность за реализацию того, как его скрипт (например — в сервис-воркере [30]) поддерживает кэш в актуальном состоянии. Элементы, сохранённые в кэше, не обновляются до тех пор, пока не будет сделан явный запрос на их обновление, срок их хранения не истекает, их можно лишь удалить из кэша. Для того чтобы открыть именованный объект кэша, можно воспользоваться командой CacheStorage.open() [31], после чего можно, обращаясь к нему, вызывать команды управления кэшем.
Кроме того, разработчик ответственен за периодическую очистку кэша. У каждого браузера имеется жёстко заданное ограничение на размер кэша, который выделяется конкретному источнику. Узнать примерное значение квоты кэширования можно, воспользовавшись API StorageEstimate [32].
Браузер делает всё, что в его силах, для того, чтобы поддерживать определённый объём доступного пространства кэша, но он может удалить кэш для некоего источника. Обычно браузер либо удаляет весь кэш, либо совершенно его не касается. Пользуясь кэшами, не забывайте о том, чтобы различать их в соответствии с версиями ваших скриптов, например, включая версию скрипта в имя кэша. Делается это для того, чтобы обеспечить безопасную работу различных версий скриптов с кэшем. Подробности об этом можно посмотреть здесь [33].
Интерфейс CacheStorage [34] представляет хранилище для объектов Cache [21]. Вот задачи, за решение которых отвечает этот интерфейс:
Cache.
Для того чтобы получить экземпляр объекта Cache, воспользуйтесь командой CacheStorage.open() [31].
Для того чтобы узнать, является ли некий объект Request [36] ключом какого-либо объекта Cache, которым управляет CacheStorage, воспользуйтесь методом CacheStorage.match() [37].
Обратиться к CacheStorage можно через глобальное свойство caches [38].

API IndexedDB [22] — это СУБД, которая позволяет хранить данные средствами браузера. Так как это позволяет создавать веб-приложения, обладающие возможностями работы со сложными наборами данных даже без подключения к интернету, такие приложения могут одинаково хорошо себя чувствовать и при наличии соединения с сервером, и без него. IndexedDB находит применение в приложениях, которым нужно хранить большие объёмы данных (например, такое приложение может быть чем-то вроде каталога фильмов некоей службы, выдающей их напрокат), и которым необязательно поддерживать постоянное соединение с сетью для нормальной работы (например — это почтовые клиенты, менеджеры задач, записные книжки, и так далее).
Здесь мы уделим IndexedDB немного больше внимания, чем остальным технологиям хранения данных на клиенте, так как, с одной стороны, другие API известны более широко, а с другой — так как СУБД IndexedDB становится всё более популярной из-за постоянного роста сложности веб-приложений.
API IndexedDB позволяет сохранять в базу и читать из неё данные объектов с использованием «ключа». Все изменения, вносимые в базу данных, происходят в транзакциях. Как и большинство подобных решений, IndexedDB следует политике одного источника [39]. В результате приложение может получить доступ только к данным, относящимся к собственному домену, но не к данным из других доменов.
IndexedDB — это асинхронное [40] API, которое можно использовать в большинстве контекстов, в том числе — в веб-воркерах [41]. Раньше существовала и синхронная [42] версия этого API, предназначенная для веб-воркеров, но её убрали из спецификации из-за того, что она была не особенно интересна веб-разработчикам.
У IndexedDB был конкурент в лице базы данных WebSQL, но работа над этим стандартом была прекращена W3C много лет назад. В то время, как и IndexedDB и WebSQL являются решениями для хранения данных на клиенте, их функционал различается. WebSQL — это реляционная СУБД, а IndexedDB — это система, основанная на индексированных таблицах.
Не стоит приступать к работе с IndexedDB, основываясь на идеях, вынесенных из опыта работы с другими СУБД. Вместо этого полезно будет внимательно ознакомиться с документацией по этой базе данных и использовать при работе с ней те методы, на которые она рассчитана. Вот краткий обзор основных концепций IndexedDB:
onsuccess и onerror, которым можно назначать прослушиватели соответствующих событий, а так же — свойства readyState, result, errorCode, анализируя которые можно узнать о состоянии запроса.
Система IndexedDB разработана в расчёте на то, что её возможностей должно хватить для решения большинства задач хранения данных на стороне клиента. Понятно, что она не является универсальной системой, подходящей для любых сценариев использования. Вот несколько ситуаций, на которые она не рассчитана:
Кроме того, работая с IndexedDB, учитывайте то, что браузер может удалить базу данных в следующих случаях:
В целом, можно отметить, что разработчики браузеров стремятся к тому, чтобы не удалять базы данных IndexedDB без крайней необходимости.
Вот сведения о поддержке IndexedDB в различных браузерах.

Поддержка IndexedDB различными браузерами
Как уже было сказано, учитывая потребности приложения, лучше всего выбирать те системы хранения данных, которые обладают широкой поддержкой браузеров и работают в асинхронном режиме, что позволяет минимизировать их воздействие на пользовательский интерфейс. Эти критерии вполне естественным образом ведут к следующим технологиям:
Автор этого материала говорит, что в компании SessionStack [48] используют различные API для хранения данных. Например, библиотека, интегрируемая в веб-приложения для сбора данных об их работе, использует куки и сессионное хранилище. Приложение, которое предназначено для воспроизведения того, что происходило на странице, использует куки-файлы для целей аутентификации пользователей.
Уважаемые читатели! Какими технологиями хранения данных на стороне клиента вы пользуетесь в своих веб-приложениях?
Автор: ru_vds
Источник [50]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/284392
Ссылки в тексте:
[1] Обзор движка, механизмов времени выполнения, стека вызовов: https://habrahabr.ru/company/ruvds/blog/337042/
[2] О внутреннем устройстве V8 и оптимизации кода: https://habrahabr.ru/company/ruvds/blog/337460/
[3] Управление памятью, четыре вида утечек памяти и борьба с ними: https://habrahabr.ru/company/ruvds/blog/338150/
[4] Цикл событий, асинхронность и пять способов улучшения кода с помощью async / await: https://habrahabr.ru/company/ruvds/blog/340508/
[5] WebSocket и HTTP/2+SSE. Что выбрать?: https://habrahabr.ru/company/ruvds/blog/342346/
[6] Особенности и сфера применения WebAssembly: https://habrahabr.ru/company/ruvds/blog/343568/
[7] Веб-воркеры и пять сценариев их использования: https://habrahabr.ru/company/ruvds/blog/348424/
[8] Сервис-воркеры: https://habrahabr.ru/company/ruvds/blog/349858/
[9] Веб push-уведомления: https://habrahabr.ru/company/ruvds/blog/350486/
[10] Отслеживание изменений в DOM с помощью MutationObserver: https://habrahabr.ru/company/ruvds/blog/351256/
[11] Движки рендеринга веб-страниц и советы по оптимизации их производительности: https://habrahabr.ru/company/ruvds/blog/351802/
[12] Сетевая подсистема браузеров, оптимизация её производительности и безопасности: https://habr.com/company/ruvds/blog/354070/
[13] Анимация средствами CSS и JavaScript: https://habr.com/company/ruvds/blog/354438/
[14] Как работает JS: абстрактные синтаксические деревья, парсинг и его оптимизация: https://habr.com/company/ruvds/blog/415269/
[15] Как работает JS: классы и наследование, транспиляция в Babel и TypeScript: https://habr.com/company/ruvds/blog/415377/
[16] Image: https://habr.com/company/ruvds/blog/415505/
[17] FileSystem: https://developer.mozilla.org/en-US/docs/Web/API/FileSystem
[18] LocalStorage: https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
[19] SessionStorage: https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage
[20] Cookie: https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
[21] Cache: https://developer.mozilla.org/en-US/docs/Web/API/Cache
[22] IndexedDB: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API
[23] filesystem: https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry/filesystem
[24] Storage: https://developer.mozilla.org/en-US/docs/Web/API/Storage
[25] Document: https://developer.mozilla.org/en-US/docs/Web/API/Document
[26] SessionStorage: https://developer.mozilla.org/en-US/docs/Web/API/Window.sessionStorage
[27] протокола HTTP: https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview#HTTP_is_stateless_but_not_sessionless
[28] Request: http://fetch.spec.whatwg.org/#request
[29] Response: http://fetch.spec.whatwg.org/#response
[30] сервис-воркере: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker
[31] CacheStorage.open(): https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/open
[32] StorageEstimate: https://developer.mozilla.org/en-US/docs/Web/API/StorageEstimate
[33] здесь: https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker_API/Using_Service_Workers#Deleting_old_caches
[34] CacheStorage: https://developer.mozilla.org/ru/docs/Web/API/CacheStorage
[35] window: https://developer.mozilla.org/en-US/docs/Web/API/Window
[36] Request: https://developer.mozilla.org/en-US/docs/Web/API/Request
[37] CacheStorage.match(): https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/match
[38] caches: https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/caches
[39] политике одного источника: http://www.w3.org/Security/wiki/Same_Origin_Policy
[40] асинхронное: https://developer.mozilla.org/en/IndexedDB#Asynchronous_API
[41] веб-воркерах: https://developer.mozilla.org/En/DOM/Using_web_workers
[42] синхронная: https://developer.mozilla.org/en/IndexedDB#Synchronous_API
[43] транзакции: https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB#gloss_transaction
[44] XMLHttpRequest: https://developer.mozilla.org/en/DOM/XMLHttpRequest
[45] этот: https://en.wikipedia.org/wiki/NoSQL
[46] Cache: https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/cache-api
[47] сервис-воркеры: https://jakearchibald.github.io/isserviceworkerready/
[48] SessionStack: https://www.sessionstack.com/
[49] Image: https://ruvds.com/ru-rub/#order
[50] Источник: https://habr.com/post/415505/?utm_campaign=415505
Нажмите здесь для печати.