Опрос
Ждете ли вы выхода привычных ноутбуков на новой Windows 10X?

Индексированное хранилище, часть 1

Напечатать страницу
10.02.2015 10:00 | dronov_va

Современные Web-обозреватели, и Microsoft Internet Explorer в том числе, постепенно обзаводятся поддержкой всё новых и новых функций. Уже никого, а в особенности пользователей мобильных устройств, не удивляет наличие в программах такого рода средств получения текущего местоположения компьютера (геолокации). Уже появились и довольно широко применяются инструменты, позволяющие хранить на локальном компьютере произвольный набор данных любого объёма (локальное и сессионное хранилища). Уже появляется поддержка средств для определения ориентации мобильных устройств, определения состояния встроенного в устройство аккумулятора, получения доступа к датчику освещённости и пр.

Давайте остановимся на инструментах, предназначенных для локального хранения данных. Локальное и сессионное хранилища дают нам возможность записать на клиентском компьютере произвольный набор элементарных значений под заданными нами именами. (В этом смысле их можно рассматривать как набор обычных переменных JavaScript, хранящих элементарные значения.)

Но локальное и сессионное хранилища в качестве значений этих "переменных" могут хранить лишь строки. Конечно, если нам нужно сохранить число или логическое значение, мы без труда сможем преобразовать его в строковый вид.

Но что делать, если нам нужно сохранить целый массив?


1.1. Введение в индексированное хранилище

Использовать индексированное хранилище (также известно как Indexed Database и IndexedDB). В результате чего мы получим ряд преимуществ:

  • Мы можем хранить там значения любого типа: строки, числа, логические величины, массивы, экземпляры любых объектов, как встроенных в JavaScript, так и пользовательских, и даже значения null и undefined.
  • Мы можем быстро получить любое значение по его первичному ключу (который можно рассматривать как величину, однозначно идентифицирующую это значение).
  • Как вариант, мы можем выполнить прямой перебор всех значений, имеющихся в индексированном хранилище.
  • Мы можем выполнить поиск значения по другим критериям, не только по его первичному ключу. Для этого достаточно создать соответствующий индекс.



Недостаток этого инструмента всего один - сложность в программировании, на взгляд автора, даже чрезмерная. Всё дело в сугубой асинхронности работы хранилища, вследствие чего, например, при запросе на извлечение значения по заданному ключу мы получим это значение не сразу же после отправки запроса, а спустя неопределённое время, - и нам обязательно придётся отслеживать момент времени, когда это значение будет получено.

Внимание!
Поддержка индексированного хранилища присутствует в Microsoft Internet Explorer 10 и более поздних его версиях.


2. Основные понятия

Терминология, применяемая при работе с индексированным хранилищем, схожа с таковой, используемой для взаимодействии с базами данных.

В первую очередь, это, конечно, база данных - сущность самого высокого порядка. Может содержать произвольное количество объектных хранилищ (см. ниже). База данных должна иметь уникальное имя, заданное в виде строки, и версию, указанную как целое число; если версия не указана, база данных будет иметь версию 1.

Каждая база данных привязывается к домену, с которого была загружена открывшая её страница. Это позволяет разделить базы данных, используемые разными сайтами.

Один Web-сценарий может работать с несколькими базами данных, и одна база данных может быть открыта сразу несколькими сценариями.

Объектное хранилище - сущность, являющаяся частью базы данных и предназначенная непосредственно для записи в него значений. Аналогично таблице обычной базы данных. Объектное хранилище должно иметь имя, заданное в виде строки и уникальное в пределах базы данных, частью которой оно является.

Собственно сохраняемое значение помещается в объектное хранилище. Как уже говорилось, оно может принадлежать к любому типу, поддерживаемому JavaScript.

Первичный ключ (о котором также упоминалось ранее) - особая величина, однозначно идентифицирующая значение, записанное в объектное хранилище. Аналогичен полю идентификатора, присутствующему в записях обычной базы данных. Может быть строкой, числом, значением даты и времени (экземпляром объекта Date) и массивом.

Поддерживаются три способа задания первичного ключа:

  • непосредственным указанием;
  • с помощью генератора ключей - механизма, генерирующего первичные ключи на основе каких-либо исходных данных;
  • с помощью пути ключа, указывающего свойство объекта, чьи экземпляры хранятся в качестве значений; значения этого свойства и будут использоваться в качестве первичных ключей.



Запрос - сущность, возвращаемая методами, которые используются для выполнения различных операций на базой данных и хранящимися в ней значениями. Каждый запрос представляет одну выполняемую над базой операцию.

Транзакция - операция или набор операций, выполняющихся над содержимым базы данных. Любая операция, производимая над базой, выполняется в виде транзакции.

И ещё один важный момент. Дело в том, что все операции над базой данных и её содержимым выполняются исключительно асинхронно. Поясним это на примере.

Пусть мы выполняем команду на соединение с базой, вызвав соответствующий метод. Этот метод вернёт нам в качестве результата упомянутый ранее запрос - сущность (а именно, экземпляр особого объекта), в данном случае представляющую операцию открытия базы. Но сама база открыта не будет! Запрос лишь сообщит нам, что операция её открытия запущена и будет завершена позже, спустя какое-то время.

Как только база будет наконец открыта, в запросе возникнет особое событие, означающее окончание выполнения операции. Нам нужно привязать к этому событию обработчик, в теле которого мы сможем выполнить последующие операции с базой данных: подключение к нужному объектному хранилищу, запрос значения по его первичному ключу и пр.

Такой подход, надо признаться, существенно усложняет программирование с применением индексированного хранилище. С другой стороны, он позволяет избежать блокировок Web-обозревателя при выполнении длительных операций над базами данных.

Внимание!
Индексированное хранилище можно использовать лишь в Web-страницах, загруженных с Web-сервера. В страницах, открытых локально, оно не поддерживается.


3. Простейшие операции с индексированным хранилищем

Что ж, с теоретической частью мы закончили. Можно приступать к изучению принципов практической работы с индексированным хранилищем. И начнём мы с выполнения самых простых операций.


3.1. Получение доступа к индексированному хранилищу

Сначала нам нужно получить доступ к хранилищу. Для чего мы используем свойство indexedDB объекта Window, представляющего окно Web-обозревателя; экземпляр этого объекта, представляющий текущее окно, доступен из переменной window.

if (window.indexedDB) {
   // Web-обозреватель поддерживает индексированное хранилище
   // Можно начинать работу
} else {
   // Web-обозреватель не поддерживает индексированное хранилище
}

{
// Web-обозреватель не поддерживает индексированное хранилище
}[/code]

Здесь мы предварительно проверяем, поддерживает ли Web-обозреватель индексированное хранилище, и начинаем с ним работу лишь в том случае, если оно поддерживается.

Свойство indexedDB хранит экземпляр объекта IDBFactory, выполняющего различные действия над самими базами данных. Он скоро нам пригодится.


3.2. Создание и открытие базы данных

Следующий наш шаг - открытие существующей базы данных или её создание, если нужная нам база ещё не существует. Для этого мы используем метод open объекта IDBFactory, формат вызова которого следующий:

[code]<экземпляр объекта IDBFactory>.open(
<имя базы данных>[,
<версия базы данных>]
)[/code]

Первый параметр указывает имя базы данных в виде строки. Если база с указанным именем не существует, она автоматически будет создана.

Второй, необязательный, параметр задаёт версию содаваемой или открываемой базы данных в виде целого числа. Если версия не указана, и база данных не существует, созданная база будет иметь версию 1.

Метод open возвращает экземпляр объекта IDBOpenDBRequest, представляющий запрос на открытие базы данных.

Например, следующий код создаёт или открывает базу данных test версии 1:

[code]var req = window.indexedDB.open("test");[/code]


3.3. Запросы и работа с ними

А теперь нам самое время рассмотреть запросы, представляющие их объекты, их свойства и события и принципы работы с ними.

Как мы уже знаем, запрос - это сущность, а именно, экземпляр особого объекта, представляющая запущенную нами асинхронную операцию, которой может быть открытие базы данных, получение, добавление, изменение, удаление значения и т. п. Имея запрос, мы можем отследить момент завершения выполнения операции и получить результат её выполнения, если она возвращает таковой: базу данных или запрошенное значение.

Любой запрос представляется объектом IDBRequest. (Единственное исключение - запрос на открытие базы данных, представляемый объектом IDBOpenDBRequest - потомка объекта IDBRequest.) Он поддерживает два события:

  • success - возникает при успешном завершении выполнении представляемой запросом операции;
  • error - возникает в случае ошибки.



Чтобы привязать обработчик к такому событию, рекомендуется пользоваться свойствами вида on<имя события>. Так, если мы хотим указать функцию dbSuccess в качестве обработчика события success запроса, хранящегося в переменной req, мы запишем такой код:

[code]function dbSuccess(evt) { . . . }
. . .
req.onsuccess = dbSuccess;[/code]

На заметку
Internet Explorer также поддерживает привязку обработчиков к событиям с помощью знакомого нам метода addEventListener. Однако другие Web-обозреватели, в частности, Mozilla Firefox, не допускают этого. Поэтому для обеспечения кроссплатформенной совместимости рекомендуется применять описанный ранее подход.

Ещё объект IDBRequest поддерживает два свойства, которые обязательно нам пригодятся:

  • result - возвращает результат выполнения операции, например, открытую базу данных или полученное из неё значение;
  • error - возвращает экземпляр объекта, представляющий возникшую при выполнении операции ошибку.



Внутри обработчика события, возникшего в запросе, мы можем получить доступ к этому запросу, обратившись к свойству target экземпляра объекта, который представляет возникшее событие. Как мы знаем, этот экземпляр объекта передаётся в функцию-обработчик единственным параметром.

Ниже приведён фрагмент кода, обрабатывающего успешное и неуспешное завершение операции. Мы можем использовать его как шаблон для написания своего кода.

[code]var req = window.indexedDB.open("test");
req.onsuccess = function (evt) {
// Получаем открытую или вновь созданную базу данных
var db = evt.target.result;
// Работаем с полученной базой данных
}
req.onerror = function (evt) {
// Выводим сообщение об ошибке
window.alert(evt.target.error);
}[/code]


3.4. Получение созданной или открытой базы данных

Вернёмся к нашей базе данных. Запущенная ранее операция по её открытию или созданию уже должна завершиться, и мы сможем получить эту базу, чтобы начать работу с ней.

Если нужная нам база данных уже существует в хранилище, то она будет открыта. При этом в запросе возникнет событие success, в обработчике которого мы сможем извлечь необходимые значения, добавить, исправить и удалить их.

Если же база данных ещё не существует, она будет создана. Как только она будет создана, в запросе возникнет событие upgradeneeded. (Это событие поддерживается объектом IDBOpenDBRequest - потомком объекта IDBRequest.) В обработчике этого события мы создадим все нужные нам структуры, а именно, объектные хранилища.

Как только обработчик события upgradeneeded завершит свою работу, будет выполнен обработчик события success. Так что мы сразу же после создания объектных хранилищ можем начать работу с ними.

В обработчиках обеих этих событий мы можем получить открытую или созданную базу данных из свойства result запроса. База данных представляется экземпляром объекта IDBDatabase.

Напоследок давайте рассмотрим пример кода, одинаково успешно обрабатывающего как открытие существующей, так и создание новой базы данных. (Обработку ошибок ради простоты выполнять не будем.)

[code]var req = window.indexedDB.open("test");
reg.onupgradeneeded = function (evt) {
// Получаем вновь созданную базу данных
var db = evt.target.result;
// Создаём объектные хранилища
}
reg.onsuccess = function (evt) {
// Получаем открытую базу данных
var db = evt.target.result;
// Работаем с ней
}[/code]

Обратим внимание, что для привязки обработчика к событию upgradeneeded мы использовали описанный ранее подход - присваивание функции-обработчика свойству on<имя события>, в нашем случае - onupgradeneeded.


3.5. Создание объектных хранилищ

Вновь созданная база данных абсолютно пуста. Так что первым же нашим действием будет создание в ней необходимых объектных хранилищ.

Для создания объектного хранилища используется метод createObjectStore объекта IDBDatabase:

[code]<база данных>.createObjectStore(
<имя объектного хранилища>[,
<параметры объектного хранилища>]
)[/code]

Первым параметром передаётся имя создаваемого объектного хранилища, указанное в виде строки. Если будет выполнена попытка создать объектное хранилище с именем, совпадающим с именем уже имеющегося хранилища, возникнет ошибка.

Вторым, необязательным, параметром передаётся экземпляр объекта Object, задающий параметры создавамого хранилища. Этот параметр указывается лишь при использовании генератора ключей или пути ключа, о которых мы поговорим позже.

Метод createObjectStore возвращает готовое объектное хранилище, представляемое экземпляром объекта IDBObjectStore. Как видим, этот метод выполняет свою работу сразу же, не заставляя нас ждать и возиться с запросами...

Что ж, за работу! Для начала создадим объектное хранилище data.

[code]var req = window.indexedDB.open("test");
req.onupgradeneeded = function (evt) {
var db = evt.target.result;
db.createObjectStore("data");
}[/code]


3.6. Добавление значений в объектное хранилище

Как и только что созданная база, новое объектное хранилище не содержит никаких данных. Так что давайте сразу же запишем в него что-нибудь.


3.6.1. Запуск транзакции

Все операции по работе с находящимися в хранилище данными - чтение, добавление, правка и удаление - выполняются в составе, или, как ещё говорят, контексте, транзакции. Поэтому перед тем как собственно добавлять значения, нам следует запустить транзакцию, и сделать это мы должны самостоятельно.

Внимание!
Из этого правила есть исключение. Внутри обработчика события upgradeneeded нам не нужно заключать операции по работе с данными в транзакцию, поскольку весь код этого обработчика уже выполняется в контексте транзакции, неявно запущенной самим Web-обозревателем. Подробнее об этом мы поговорим потом.

Транзакцию запускает метод transaction объекта IDBDatabase:

[code]<база данных>.transaction(
<имена объектных хранилищ>[,
<режим транзакции>]
)[/code]

Первый параметр задаёт имена объектных хранилищ, вовлечённых в транзакцию, то есть тех, данными из которых мы будем манипулировать внутри этой транзакции. Если затрагиваются данные лишь из одного хранилища, его имя передаётся в виде строки. Если будут затронуты данные из нескольких хранилищ, их имена, также заданные в виде строк, следует указать в массиве. Если же мы планируем работать со всеми хранилищами, что есть в базе, мы передадим первым параметром значение свойства objectStoreNames объекта IDBDatabase, которое хранит массив имён всех хранилищ базы.

Второй, необязательный, параметр задаёт режим транзакции в виде одной из строк:

  • "readonly" - допускается только чтение данных; значение по умолчанию;
  • "readwrite" - допускается и чтение, и запись данных.



На заметку
Также поддерживается режим транзакции versionchange, позволяющий изменять структуру базы данных, то есть создавать новые объектные хранилища. Однако явно запустить такую транзакцию нельзя - это приведёт к возникновению ошибки. Транзакция в режиме versionchange запускается самим Web-обозревателем в обработчике события upgradeneeded.

Метод transaction возвращает запущенную транзакцию, представляемую экземпляром объекта IDBTransaction.

Вот пример кода, запускающего транзакцию, которая затрагивает хранилище data и разрешает запись данных:

[code]var tran = db.transaction("data", "readwrite");[/code]

А этот код запускает транзакцию, затрагивающую хранилища data и depot и разрешает лишь чтение данных:

[code]var tran = db.transaction(["data", "depot"]);[/code]

Нужно заметить ещё один момент. Транзакции, выполняющие операции чтения из базы, могут выполняться одновременно. Однако транзакции, что производят какие-либо изменения в содержимом базы (добавляют, изменяют или удаляют значения), выполняются строго по очереди, в том порядке, в котором они были запущены.


3.6.2. Выбор объектного хранилища

Далее нам необходимо выбрать объектное хранилище, с содержимым которого мы будем работать. Для этого мы вызовем метод objectStore объекта IDBTransaction:

[code]<транзакция>.objectStore(
<имя объектного хранилища>
)[/code]

Единственным параметром указывается имя объектного хранилища в виде строки. Отметим, что это хранилище должно присутствовать в перечне хранилищ, вовлечённых в транзакцию, который указывается в вызове метода transaction (см. ранее).

Метод возвращает запрошенное объектное хранилище в виде экземпляра объекта IDBObjectStore.

[code]var os = tran.objectStore("data");[/code]


3.6.3. Собственно добавление значения

Вот теперь мы можем добавить в хранилище новое значение. Для чего вызовем метод add объекта IDBObjectStore:

[code]<объектное хранилище>.add(
<добавляемое значение>[,
<первичный ключ>]
)[/code]

Первым параметром передаётся само добавляемое в хранилище значение; оно может быть любого типа.

Второй, необязательным, параметр задаёт первичный ключ для этого значения. Если в объектном хранилище задан генератор ключей или путь ключа, этот параметр не указывается. (О генераторах ключей и пути ключа мы поговорим потом.)

Указанный в вызове метода первичный ключ гарантированно не должен существовать в хранилище. Если мы попытаемся сохранить два значения с одинаковым первичным ключом, то получим ошибку.

Операция добавления значения выполняется асинхронно. Поэтому метод add возвращает запрос, представляющий эту операцию и представляемый экземпляром объекта IDBRequest. Мы можем отследить момент, когда значение будет добавлено в хранилище, привязав обработчик к событию success этого запроса.

В обработчике события success мы можем получить доступ к первичному ключу добавленного значения. Для этого достаточно обратиться к свойств result запроса, что будет передан в обработчик в свойстве target события.

Этот фрагмент кода добавляет в выбранное нами ранее хранилище строковое значение:

[code]var req2 = os.add("Тест!!!", "test1");
req2.onsuccess = function (evt) {
window.alert("Значение с первичным ключом " + evt.target.result +
" было успешно добавлено.");
}
req2.onerror = function (evt) {
window.alert("Значение не было добавлено.");
}[/code]

А этот фрагмент добавляет туда же значение, представляющее собой экземпляр объекта:

[code]var req3 = os.add({a: "a", b: 1}, "test2");[/code]

Здесь мы не выполняем проверку, было ли значение реально добавлено. Поскольку мы можем сделать это на уровне транзакции.


3.6.4. Отслеживание завершения транзакции

Только что мы узнали, как проверить, было ли добавленное нами значение записано в хранилище. Однако эта проверка выполняется на уровне каждого добавляемого значения, что в случае, если таких значений много, может быть неприемлемо. Гораздо удобнее отследить момент добавления всех этих значений на уровне транзакции.

Объект IDBTransaction, представляющий транзакцию, поддерживает три события:

  • complete - возникает в случае успешного завершения транзакции, когда все операции, выполняющиеся в её контексте, были благополучно выполнены;
  • error - возникает в случае ошибки;
  • abort - возникает, если транзакция была отменена либо вызовом метода abort, либо самим Web-обозревателем.



Следовательно, привязав обработчик к событию complete транзакции, мы можем отследить момент её успешного завершения:

[code]var tran = db.transaction("data", "readwrite");
tran.oncomplete = function () {
window.alert("Данные были успешно добавлены.");
}
var os = tran.objectStore("data");
var req = os.add("Тест!!!", "test1");
var req = os.add({a: "a", b: 1}, "test2");[/code]


3.6.5. Прерывание транзакции

Транзакции завершаются самим Web-обозревателем, так что нам не придётся выполнять эту операцию самостоятельно (в отличие от разработчиков, имеющих дело с СУБД). Однако возможность прервать транзакцию у нас есть.

Прервать выполняющуюся транзакцию можно, вызвав не принимающий параметров и не возвращающий результата метод abort объекта IDBTransaction.

[code]var tran = db.transaction("data", "readwrite");
tran.onabort = function () {
window.alert("Транзакция была прервана.");
}
var os = tran.objectStore("data");
var req = os.add("Тест!!!", "test1");
tran.abort();[/code]

В результате выполнения этого кода никакого нового значения в хранилище добавлено не будет.

Web-обозреватель может прервать транзакцию самостоятельно, если посчитает, что она выполняется слишком долго (что, как правило, происходит вследствие ошибки в сценарии). Это тоже следует иметь в виду, особенно при отладке.


3.7. Получение сохранённого значения

Итак, мы занесли в объектное хранилище несколько значений. Давайте попробуем извлечь их оттуда.

Нам понадобится метод get объекта IDBObjectStore:

[code]<объектное хранилище>.get(
<первичный ключ>
)[/code]

Единственным параметром передаётся первичный ключ искомого значения. Он уже должен существовать в хранилище; если мы попытаемся выполнить поиск по несуществующему первичному ключу, то получим ошибку.

Метод get возвращает запрос, поскольку операции чтения также выполняются асинхронно. В обработчике события success этого запроса мы можем извлечь найденное значение из свойства result запроса, полученного в свойстве target события.

Вот пример:

[code]var tran = db.transaction("data");
var os = tran.objectStore("data");
var req = os.get("test1");
req.onsuccess = function (evt) {
window.alert(evt.target.result);
}
req.onerror = function (evt) {
window.alert("Искомое значение не найдено.");
}[/code]


3.8. Изменение сохранённого значения

Изменить значение позволяет метод put объекта IDBObjectStore. Он вызывается так же, как и уже знакомый нам метод add.

Если вторым параметром при вызове метода put был указан уже существующий в хранилище первичный ключ, соответствующее ему значение будет перезаписано тем, что мы указали первым параметром. Если же такого первичного ключа нет, заданное значение будет добавлено в хранилище, как если бы мы вызвали метод add.

Метод возвращает в качестве результата запрос. Свойство result этого запроса будет хранить первичный ключ изменённого или добавленного значения.

Изменим сохранённое ранее в базе значение с первичным ключом test1:

[code]var tran = db.transaction("data");
var os = tran.objectStore("data");
var req = os.put("Другой тест!!!", "test1");
req.onsuccess = function (evt) {
window.alert("Значение с первичным ключом " + evt.target.result +
" было успешно изменено.");
}[/code]

А теперь изменим значение свойства b экземпляра объекта, сохранённого под первичным ключом test2:

[code]var tran = db.transaction("data");
var os = tran.objectStore("data");
var req = os.get("test2");
req.onsuccess = function (evt) {
var v = evt.target.result;
v.b = 2;
var req2 = os.put(v, "test2");
req.onsuccess = function (evt) {
window.alert("Значение с первичным ключом " + evt.target.result +
" было успешно изменено.");
}
}[/code]


3.9. Удаление значения

Наконец, для удаления сохранённого значения мы используем метод delete объекта IDBObjectStore. Он вызывается так же, как и метод get, описанный ранее.

Первичный ключ, заданный при вызове этого метода, гарантированно должен присутствовать в хранилище. Если мы передадим методу несуществующий первичный ключ, возникнет ошибка.

Метод delete возвращает запрос. Свойство result этого запроса не будет содержать никакого значения.

Удалим ненужное значение с первичным ключом test1:

[code]var tran = db.transaction("data");
var os = tran.objectStore("data");
var req = os.delete("test1");
req.onsuccess = function (evt) {
window.alert("Значение с первичным ключом 'test1' было успешно изменено.");
}[/code]


3.10. Выполнение операций по обработке данных в обработчике события upgradeneeded

Ранее мы говорили, что операции по работе с данными - чтение, добавление, правка и удаление значений, - выполняемые в обработчике события upgradeneeded, не должны заключаться в транзакцию. Дело в том, что все операции, что мы выполним в обработчике этого события, уже будут работать в контексте транзакции, неявно запущенной самим Web-обозревателем.

Давайте убедимся сами:

[code]reg.onupgradeneeded = function (evt) {
var db = evt.target.result;
var os = db.createObjectStore("data");
os.add("Тест!!!", "test");
}[/code]

Здесь мы выполнили операцию по добавлению нового значения, не запуская предварительно транзакцию. (Более того - если мы всё же запустим там транзакцию явно, получим сообщение об ошибке.)

Отметим, что транзакция в обработчике события upgradeneeded запускается в особом режиме versionchange. Только этот режим даёт право на изменение структуры базы данных. И также отметим, что запустить в нём транзакцию явно, указав в вызове метода transaction объекта IDBDatabase вторым параметром строку "versionchange", нельзя - это приведёт к ошибке.


3.11. Практическое занятие

Настало время закрепить полученные знания. В качестве примера напишем страницу, которая будет подсчитывать, сколько раз она была загружена, и записывать это значение в индексированном хранилище. Это позволит нам применить на деле все приёмы, что мы выучили к этому времени.

Вот код этой страницы:

[code]<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Индексированное хранилище</title>
<script>
function showError(evt) {
window.alert(evt.target.error);
}

window.addEventListener("load", function() {
if (window.indexedDB) {
var req = window.indexedDB.open("test");

req.onupgradeneeded = function (evt) {
var db = evt.target.result;
var os = db.createObjectStore("data");
var req2 = os.add(0, "counter");
req2.onerror = showError;
}

req.onsuccess = function (evt) {
var db = evt.target.result;
var tran = db.transaction("data", "readwrite");
var os = tran.objectStore("data");
var req3 = os.get("counter");

req3.onsuccess = function (evt) {
var v = evt.target.result;
v++;
var divOutput = document.getElementById("output");
divOutput.textContent = v;
var req4 = os.put(v, "counter");
req4.onerror = showError;
}

req3.onerror = showError;
}

req.onerror = showError;
} else {
}
}, false);
</script>
</head>
<body>
<div id="output"></div>
</body>
</html>[/code]

Для хранения данных мы создали базу данных test, а в ней - объектное хранилище data. Само значение количество посещений этой страницы мы сохраним под первичным ключом counter.

Сразу при создании объектного хранилища, в обработчике события upgradeneeded, мы запишем в него значение 0. Впоследствии при каждой загрузке страницы мы будем извлекать это значение, инкрементировать его (увеличивать на единицу), выводить на экран и сохранять снова.

Внимание!
Чтобы протестировать эту страницу, нам потребуется загрузить её с Web-сервера. Можно использовать любую программу Web-сервера (например, Microsoft IIS), установленную локально.

Что ж, простейшими приёмами работы с индексированным хранилищем мы овладели. Пора переходить к рассмотрению более сложных приёмов.


Дополнительные материалы




Окончание следует...


dronov_va, MSInsider.ru Team
Январь-февраль 2015

Комментарии

Не в сети

Интересная и полезная статья. Спасибо!

13.11.17 13:16
0
Для возможности комментировать войдите в 1 клик через

По теме

Акции MSFT
210.33 0.00
Акции торгуются с 17:30 до 00:00 по Москве
Все права принадлежат © ms insider @thevista.ru, 2020
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.085 секунд (Общее время SQL: 0.019 секунд - SQL запросов: 47 - Среднее время SQL: 0.00039 секунд))
Top.Mail.Ru