Сохраняем данные пользователя в браузере с помощью IndexedDB
Демонстрационная версия / Скачать материала по данной статье
IndexedDB API предоставляет вам возможность хранить ключи пользователя к определенным закрытым данным прямо в браузере. Данное приложение поддерживается большим количеством браузеров (благодаря shim, оно может работать даже в старых браузерах).
Это значит, что в случае необходимости, у вас есть возможность сохранять постоянный набор данных в браузере пользователя - независимо от подключения к Интернету. Однако его недостатком является то, что IndexedDB это очень громоздкое приложение, которое к тому же сложно в использовании.
К счастью, есть крошечная библиотека, которая может помочь нам избавиться от значительной части головной боли. Она называется db.js, и в этой статье я расскажу вам, как ее использовать.
Как использовать db.js
IndexedDB использует в своей работе такие элементы, как обратные вызовы, мониторинг ошибок и применение большого количества временных переменных. Db.js автоматизирует их и предоставляет более понятный и легкий для работы интерфейс.
Любой поклонник JQuery будет этому рад. Библиотека даже использует тот же механизм откладывания /обещаний, что и JQuery. Если вы впервые слышите о вещах, которые я только что перечислил, не волнуйтесь, все станет понятнее, когда мы рассмотрим сам код.
Мы создадим небольшое демонстрационное приложение. В нем мы сделаем следующее:
- Во-первых, определим схему нового ключа/значения хранилища$
- Попробуем войти в базу данных, и если все прошло хорошо, тогда перейдем к следующему шагу;
- Настроить ожидание событий на клик по элементу «Добавить». В теле блока считывания мы вставим запись в базу данных и выведем элемент на страницу;
- И наконец, когда элемент выбран, удалим соответствующую запись из базы данных и удалим элемент со страницы.
Помимо того, что все это осуществляется очень быстро, эти операции будут постоянными. Так что, когда вы обновите страницу или закроете браузер, данные будут в нем сохранены.
В реальном приложении вам понадобится синхронизировать содержимое хранилища IndexedDB с сервером, но мы сегодня этого делать не будем.
Код
Первым этапом у нас будет определение схемы нашего хранилища данных. В отличие от реляционных баз данных, например, таких, как MySQL, здесь мы не имеем дела с предопределенными столбцами и типами.
IndexedDB может содержать произвольные объекты JavaScript в пределах одного хранилища данных. На этом этапе существует только одно требование – опционально выбрать и индексировать поля.
Независимо от того, хотите ли вы задать автоматическое добавление или вручную определить ноль или последующие индексы.
assets/js/script.js
// Используем библиотеку db.js library, чтобы определить схему,
// и считывать событие
db.open({
name: 'database',
version: 2,
schema: {
items: {
key: {
keyPath: 'id',
autoIncrement: true
},
indexes: {
color: { unique: false }
}
}
}
})
Задав индекс, мы сообщаем IndexedDB, что система должна искать этот параметр в объектах, которые вы добавляете в хранилище данных. Затем вы сможете отбирать и сортировать все объекты, которые имеют данный признак.
В приведенном выше примере я определяю индекс по параметру цвета и сообщаю db.js, что он не будет уникальным (в противном случае я мог бы хранить только один объект с таким цветом).
На самом деле я не использую данный признак в своем приложении, но я решил включить его, чтобы показать вам, как это делается. Если вы захотите обновить схему, вам нужно будет аналогично добавить еще одну запись.
Как и в других приложениях, открытие базы данных с помощью IndexedDB является асинхронным и в некоторых случаях может выдавать ошибку (браузер не поддерживает приложение, количество записей некорректно или пользователь не авторизовался).
После открытия базы данных мы должны запустить обратный вызов метода done(), чтобы убедиться, что все прошло успешно. Мы также получаем ссылку на объект сервера, который нам нужен, чтобы выполнять запросы:
db.open({
name: 'database',
version: 2,
schema: {
items: {
key: {
keyPath: 'id',
autoIncrement: true
},
indexes: {
color: { unique: false }
}
}
}
}).done(function(server){
// База данных успешно открыта. Мы можем
// выполнить операцию с использованием переменной сервера.
// Ожидаем, когда документ будет готов, так как мы
// будем работать с dom
$(function() {
// Кэшируем некоторые селекторы
var add = $('#add'),
items = $('#items');
var colors = ['blue', 'green', 'yellow', 'pink'];
// При dom.ready выбираем все элементы и обновляем список #items
server.items.query().filter().execute().done(function(results){
if(!results){
return;
}
$.each(results, function(){
createItem(this);
});
});
// Ожидание клика по кнопке «Добавить»
add.click(function(){
var item = {
text: (new Date()).toTimeString(),
color: colors[ Math.floor( Math.random()*colors.length )]
};
server.items.add(item).done(function(){
createItem(item);
});
// Если вы хотите обновить элементы, тогда используйте:
// server.items.update({id:123, color:'pink', text:'asdf'});
});
// Когда элемент выбирается (кликается), удаляем его из базы данных.
$('#items').on('click', 'li:not(#add)', function(){
var item = $(this);
server.items.remove( item.data('id') ).done(function(){
item.fadeOut();
});
});
function createItem(item){
var tmp = $('<li><p></p></li>');
tmp.addClass( item.color )
.data('id', item.id)
.find('p').text( item.text );
items.prepend(tmp);
}
});
}).fail(function(error){
console.error("An error occured: ", error);
});
В процессе обратного запроса мы:
- ожидаем события document.ready;
- выбираем все существующие элементы из базы данных и выводим их на странице;
- ожидаем клика по кнопке «Добавить» и создаем новый элемент;
- ожидаем клика по записи самого элемента и удаляем его из базы данных;
- определяем функцию обратного вызова для создания элементов и добавления их на страницу.
В случае сбоя, мы просто выводим на консоль сообщение об ошибке. На этом наш простой пример применения IndexedDB завершен!