PersistJS + TaffyDB: Как поселить почти настоящую базу данных в браузер. Часть 2

Ключевой частью любого приложения, и веб-приложение не исключение, является хранение данных. Помимо того, что данные нужно сохранять между перезапусками браузера или компьютера клиента, не менее важным является наличие средств быстрого и удобного поиска информации. И эти средства есть. Есть средства, предусмотренные стандартом html5, пусть и не поддерживаемые пока всеми браузерами. Есть средства, созданные как несовместимые расширения, доступные только в определенных версиях браузеров. В крайнем случае, есть возможность организовать хранение данных с помощью flash. И для того, чтобы рядовой веб-разработчик не занимался складыванием паззла из десятка возможных альтернатив технологий хранения данных и поддерживающих их браузеров, появились javascript-библиотеки, предлагающие унифицированный интерфейс взаимодействия с доступными в браузере технологиями хранения данных.

В прошлый раз я начал рассказ об одной из самых известных javascript-библиотек, прячущих в себе различные средства хранения данных внутри браузера. Библиотека persistjs представляет собой “обертку” над следующими технологиями 'gears', 'localstorage', 'whatwg_db', 'globalstorage', 'flash', 'ie', 'cookie'. Последовательно перебирая эти методики, persistjs находит ту, которая доступна у конкретного клиента. Дальнейшая работа с библиотекой не зависит от того, какой механизм хранения данных используется внутри persistjs. Важным моментом является то, что перечисленные выше 8 технологий хранения данных далеко неравнозначны и отличаются как по объему хранящейся информации, так и по алгоритмам хранения и поиска. Проще говоря, всегда помните, что из всех возможных механизмов хранения данных у клиента в худшем случае может быть включена поддержка только cookie, а, значит, в вашем распоряжении будет не более чем 4 килобайта места для хранения данных. Также не стоит даже близко сравнивать возможности хранилища данных, построенных на использовании настоящей реляционной базы данных sqlite (вариант, используемый в технологиях google gears и whatwg_db). Помните, что “наименьшим общим знаменателем” является тройка функций для того, чтобы сохранить информацию, загрузить и удалить ее.

В следующем примере я покажу, как можно подключить к html-файлу библиотеку persistjs (предварительно загруженную с сайта >>><<>>
<<>>
<<>>
<<>>
<<>>Some content<<>>
<<>>

Конечно, вызывать функцию инициализации базы данных persistjs внутри обработчика события onLoad не правильно, и лучше всего было бы вызвать функцию initDb при наступлении события onDomReady. Так как, наверняка, по ходу создания веб-приложения вы будете использовать какую-нибудь javascript-библиотечку, например, jquery или Yahoo UI, то задача привязки к событию “дерево DOM загружено” не составит для вас сложности. Вот, к примеру, как будет выглядеть такой код для YUI:
YAHOO.util.Event.onDOMReady(initDb);

Или для jquery:
$(document).ready(initDB);
В любом случае, выполнять инициализацию persistjs можно только, когда html-код страницы был загружен, так как это необходимо для таких стратегий хранения данных, как ‘flash’ и ‘ie’. Теперь я приведу код функции initDB:
var storage = null;
function initDB(){
storage = new Persist.Store('storage_1', { swf_path: 'assets/persist.swf' });
alert (‘храним данные с помощью ’+Persist.type);
}

Первым параметром при создании объекта Persist.Store служит имя хранилища. Вы можете создать неограниченное количество хранилищ, но на имена каждого из них накладывается ограничение: имя должно начинаться с латинской буквы и не содержать спецсимволов. Так как за persistjs скрывается целых восемь стратегий хранения данных, то для некоторых из них необходимо указывать специальные настройки. Практически единственной полезной настройкой является параметр swf_path – путь к flash-ролику, с помощью которого persistjs будет сохранять информацию, если стратегии 'gears', 'localstorage', 'whatwg_db', 'globalstorage' не подошли. Сам файл flash-ролика приложен к дистрибутиву persistjs и занимает всего лишь половинку (ЧЕГО?немного места). Параметры domain, expires и path нужны для “последней” стратегии cookie и задают домен, для которого будут доступны сохраненные данные, затем идет срок хранения данных и каталог на сервере (только файлы, размещенные в рамках данного каталога, будут иметь доступ к сохраненной информации). К сожалению, вопрос наличия для других технологий хранения данных способа указать время жизни информации, наличие средств “расшарить информацию” между несколькими поддоменами сети, остался без положительного ответа. Также нет положительного ответа и для вопроса: можно ли информацию, сохраненную на веб-странице с помощью браузера “A”, увидеть, если открыть ту же страничку в браузере “B”?. Единственным исключением здесь является методика хранения данных с помощью flash-ролика. В этом случае вы можете сохранить данные на веб- странице, например, в firefox, а затем открыть ту же страницу в opera и увидеть сохранные ранее данные.

Вернемся назад к описанию шагов, выполняемых persistjs после вызова “new Persist.Store”. Здесь persistjs создаст хранилище (тип доступных хранилищ был определен еще раньше, сразу после завершения загрузки файла persist.js). Когда я запустил пример в браузере chrome, то появилось диалоговое окно (см. рис. 1), в котором у меня спросили, можно ли разрешить сайту работать с gears. Если ответить на вопрос положительно, то persistjs создаст простенькую табличку из двух полей: “ключ” и его “значение”. Если инициализировать persistjs в браузере opera 10, то на страницу будет внедрен flash-ролик.

Браузер IE 8 и mozilla firefox 3 будут хранить данные с помощью domStorages (на рис. 4 показано то, как можно в настройках IE включать и отключать domStorages). Если вы приверженец safari, то у вас данные будут храниться в базе данных whatwg_db (устройство таблички для хранения информации точно такое, как и в случае с google gears).

На рис. 3 я показал, как выглядит окно настроек safari, где вы можете увидеть список всех баз данных, которые были зарегистрированы на вашем компьютере; там же вы можете изменять размер пространства для каждой из баз данных. Небольшим недостатком persistjs является отсутствие возможности выполнить проверку, какие технологии хранения данных доступны, без того, чтобы создавать хранилище. C другой стороны, вы можете воспользоваться следующим несложным тестом:
alert ('localStorage = ' + window.localStorage);
alert ('sessionStorage = ' + window.sessionStorage);
alert ('safari whatwg_db = ' + window.openDatabase);
alert ('globalStorage = ' + window.globalStorage);
alert (‘IE userData = ' + window.ActiveXObject);
alert (‘gears = ' + (window.google && window.google.gears));

Еще одним недостатком persistjs является то, что список и последовательность, в которой persistjs перебирает альтернативные методики хранения данных, нельзя менять. Фактически, если вы решили повысить приоритет domStorages и поставить его перед gears-базой данных, то вам придется править код самой библиотеки persist.js (хотя разобраться в 10 килобайтах грамотно написанного кода совсем несложно). Еще одна недоработка в persistjs будет понятна, если рассмотреть следующий сценарий. Предположим, что в браузере есть формальная поддержка google gears, и в этом случае браузер спросит у клиента разрешение на сохранение данных. Но если клиент ответит отказом, то persistjs не продолжит перебор других методик сохранения данных и окажется в неопределенном положении. Продолжая тему недоработок в persistjs, можно отметить потенциальную проблему “гонок потоков” при работе с flash-хранилищем. Дело в том, что как только вы вызвали метод “new Persist.Store”, persistjs внедряет на html- страничку flash-ролик, функции которого впоследствии и вызываются всякий раз, когда нужно сохранять или загружать информацию. Но хотя swf-файл занимает всего половинку килобайта, есть маленькая вероятность того, что вы вызовете метод чтения или сохранения данных в хранилище еще до того, как flash-ролик был загружен. И это не говоря о том, что flash-трафик мог быть элементарно “срезан” корпоративным proxy-сервером; и вы никогда об этом не узнаете. Еще одним недостатком работы с flash-хранилищем является некорректная обработка ситуации, когда информация, которую вы хотите сохранить, не умещается в 100 килобайтах. 100 кб – это ограничение по-умолчанию на размер flash-хранилища. В практике, если вам не хватает выделенного места, то всегда можно попросить пользователя выделить еще немножко пространства. Чтобы отчетливее понимать, о чем я говорю, советую открыть пример исходного кода файла PersistStore.as и посмотреть на код функции “set” (сохранение информации в хранилище). Технически, когда вы внутри flash-ролика вызываете метод flush для сохранения изменений, то flash-player проверит, не будет ли текущий лимит места для хранения sharedobject превышен. И если это так, то метод flush вернет как значение специальную строку “pending”, а на экране, на фоне flash- ролика, появится всплывающее окошко с настройками flash, где вам предложат увеличить место, отведенное для хранения данных (см. рис. 5).

Впоследствии вы можете просмотреть список flash-хранилищ, которые были созданы различными сайтами у вас на компьютере, с помощью размещенного на сайте adobe “Диспетчера параметров adobe flash” ( сайт ). Интересен тот факт, что flash-player покажет окошко с запросом на увеличение размера хранилища только в том случае, если размер ролика менее чем 215 на 138 пикселей, то окно запроса не будет показано. Если flash-ролик спрятан не за счет нулевого размера, а за счет позиционирования за границы экрана – то диалоговое окно вы также не увидите. Как вывод: недостатков в реализации “моста” между persistjs и flash хватает. И если вы предполагаете, что основная аудитория вашего сайта – это посетители, у которых в браузере включен flash, а наличие альтернативных методик хранения данных, таких как gears или domStorages, маловероятно, то лучше всего отказаться от использования persistjs и познакомиться с проектом dojo ( сайт ). Dojo – огромная по возможностям (и соответственно, по размеру) javascript библиотека, предлагающая и средства для создания сложных интерфейсов пользователя, и общение с сервером (ajax). Есть в составе dojo и средства для организации хранения данных внутри flash-контейнера, а для того, чтобы “совсем маленький” модуль flash storage не потянул за собой как зависимости сто тысяч javascript- файлов, мы можем собрать версию dojo под свои потребности. Как это сделать, описано в dojo-книге по адресу сайт book-0-9/part-4-meta-dojo/package-system-and-custom-builds . Если инструкция покажется сложной, и вы не захотите вникать в подробности работы dojo только ради одной функции, то вы можете воспользоваться наработками команды сайт Они взяли из dojo только необходимый функционал для работы с flash-хранилищем и оформили это в виде отдельной библиотеки SRAX.Storage.

Возвращаясь к примеру работы с persistjs: после того как вы создали объект storage, у вас в наличии пять функций: load, save, get, set, delete. Первые две из них используются только в том редком случае, если клиент пользуется браузером IE 6 или 7, и в его наличии только технология ‘ie’ (подробный рассказ о том, как внутри устроена технология userData behavior и ее альтернативы, можно найти по адресу
сайт А вот пример работы функций set, get и delete:
// сохраняем информацию
storage.set(‘userName', ‘Ronald’);
// загружаем ее
storage.get('userName, function(if_ok, value) {
if (if_ok) alert (‘userName = ’ + value);
});
// и удаляем
storage.remove('userName, function(if_ok, old_value) {
if (if_ok) alert (‘value was deleted = ’ + value);
else alert (‘old value cannot be found’);
});

С использованием функции “set” вопросов не возникает, так как она принимает всего два параметра: имя переменной и значение, которое нужно сохранить. А вот пример работы с функциями “get” и “delete” сложнее. Дело в том, что некоторые из технологий хранения данных предполагают работу в асинхронном режиме. То есть вызов метода “загрузить информацию” не сразу же возвращает результат, а начинает выполнять свою работу параллельно с основным потоком команд приложения. А для того чтобы сигнализировать о завершении работы, вызывает специальную “callback” или функцию обратного вызова, или обработчик события “операция завершена”. Так, в примере callback-функция для операции чтения (get) принимает два параметра: первый из них – is_ok – обозначает признак успешности операции, а второй параметр хранит собственно загруженную из хранилища информацию. В случае операции delete callback-функция также принимает первым параметром признак того, смог ли persistjs найти запись, подлежащую удалению и если это так, то второй параметр функции хранит старое значение удаляемой переменной.

Сегодня я планировал завершить рассказ о совместном использовании persistjs и taffydb, но увлекся и не успел перейти к рассказу о том, как можно сохранять не простые пары “ключ и значение”, но сложные объекты с помощью taffydb. А может, это и к лучшему, так как в следующий раз я смогу полностью посвятить статью не только taffydb, но и ее “подружке ” jlinq.

black-zorro@tut.by black-zorro.com


Компьютерная газета. Статья была опубликована в номере 20 за 2009 год в рубрике программирование

©1997-2022 Компьютерная газета