Разработка с использованием WEB SQL DB и Local Storage

    Совсем недавно на хабре был пост, посвященный работе с WEB SQL DB. Одно из полезных применений локальных баз данных – работа в оффлайн режиме. Кроме этого, я покажу еще один вариант работы, когда вместо sql используется local storage, который поддерживается уже большим количеством браузеров.

    Определение offline режима


    Для начала определим, что мы работаем в offline режиме. Способов несколько. Во-первых, мы можем послать запрос, и в случае неудачи начинать работать в нужном режиме. Но HTML5 позволяет определить это более простым способом, а именно вот так
    navigator.onLine

    К сожалению, это будет работать только в Opera и Firefox (www.html5demos.com/ хороший сайт, показывающий поддержку той или иной фичи браузерами).
    Определив, что мы в оффлайне, мы можем переходить к дальнейшей работе. Важно помнить, что к этому моменту, все необходимые нам ресурсы должны быть закешированы. Подробнее о создании кэша для оффлайн приложений можно прочитать тут. А на StackOverflow можно почитать дискуссию о том, какой же метод все таки удобнее.

    Работаем с WEB SQL DB



    Работать с базой достаточно просто

    Вначале создадим ее
    db = openDatabase("TestDB", "1.0", "HTML5 Database", 200000);.

    В функцию создания базы данных передаются следующие параметры:
    • Название базы данных
    • Ее версия
    • Отображаемое имя
    • Размер в байтах

    Далее открываем транзакцию и выполняем нужные нам действия
    db.transaction(function(tx)
        {
          tx.executeSql("DELETE FROM tbl_test WHERE id = ?", [item.id]);
        });


    И далее все в таком духе. Я бы хотел предложить альтернативный вариант, а именно библиотеку jQT Database
    Вот тут можно прочитать как работает данный плагин. А скачать можно тут, если попытаться скачать его по ссылке, данной в первом источнике ничего не выйдет.
    Вкратце, как оно работает.

    Инициализируем базу:
    jQT.dbOpen(“name”, “version”,”descriptione”, size);

    Создаем таблицу:
    jQT.dbCreateTables(json);

    Вставляем строки:
    jQT.dbInsertRows(json);

    Селектим строки:
    jQT.dbSelectAll(“table”, callback(result));

    Удаляем строки:
    jQT.dbDeleteRow(“table”,”key”,”value”);

    Удаляем таблицу:
    jQT.dbDropTable(“table”);

    Выполнить запрос:
    jQT.dbExecuteQuery(“Query”,”Debug text”, callback(result));


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

    Работаем с Local storage



    Теперь проведем всю ту же работу, но только с использованием local storage. Сначала заведем само хранилище

    var storage = window.localStorage;


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

    storage.operations = ""


    Теперь перед нами стоит вопрос, в том как организовать хранение данных. Моим решением стало хранение текстового варианта xml и его последующее преобразование. (На самом деле в моем случае решение было достаточно очевидным и, наверное, единственным, так как веб-сервис возвращал мне именно xml)

    Выполняем запрос на сервер (я использую jQuery и, думаю, использовать этот код в остальных фреймворках будет несложно).

     $.ajax({
        url: '/operations/get/',
        type: 'POST',
        success: function(res) {
          var successful = $(res).find("successful").text();
          if (successful == "true") {        
            storage.operations = "<result>";
            var jobz = $(res).find("return").children();
            jobz.each(function() {
              var nodName = $(this)[0].nodeName;          
              if (nodName == "OPERATIONS") {
                var operation = $(this);
                storage.operations += "<operations>" + operation.html() + "</operations>";
              }
            });       
            storage.operations += "</result>";

          } else {        
            storage.operations += "<?xml version='1.0' encoding='utf-8'?><result></result>";
          }      
        }
      });


    Итак, мы выполнили запрос. Так как результат у нас xml, то для того, чтобы работать с ним как с DOM объектом в jQuery достаточно просто обернуть его $(). К сожалению это не работает в Internet Explorer, где для перевода текста в DOM объект необходим следующий код

    function getXml(text) {
      try {
        var xmlDocument = new ActiveXObject("Microsoft.XMLDOM");
        xmlDocument.async = "false";
        xmlDocument.loadXML(text);
        return xmlDocument;
      } catch(e) {
        alert(e.description);
      }
      return null;
    }


    Почитать про работу с веб-сервисами в IE можно тут.

    Если запрос прошел удачно, то мы выбираем всех потомков корневого узла (в моем случае они могут быть нескольких типов) и оборачиваем его нужными тегами. Замечу, что вызов .html() вернет нам именно код с тегами, в то время как .text() вернет только содержимое внутри тегов.

    Теперь чтобы получить, то что мы сохранили делаем следующую функцию

    function getOperationsFromStorage() {
      return $(storage.operations).find('operations');
    }


    Работать с ней можно следующим образом

    getOperationsFromStorage().each(function() {
      var id = $(this).find('id').text();
      alert("Find entitie with id "+id);      
    });


    Как видно, мы каждый раз оборачиваем this $() и вызываем у него метод .find(). Если у нас имеется вложенные сущности, то добраться до них можно следующим образом

    $(this).find("otherInfo").each(function() {
       var name = $(this).find("name").text();
       alert(“Found inline tag value ”+name);
    });


    Остался еще один вопрос, как обновлять наш объект. Я делаю это следующим образом.

    var s = "<operations>";
    s += "<id>" + someId+ "</id>";
    s += "<type>"+type+"</type>";
    s += "</operations>";
    var text = storage. operations;
    text = text.substring(0, text.length - 9);
    text += s + "</result>";
    storage. operations = text;


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

    Надеюсь, что теперь работа по созданию оффлайн приложений станет проще.

    P.S.: В завершении хотелось бы рассказать о библиотеке Modernizr, которая позволяет определять поддержку той или иной фичи браузером.
    Метки:
    • +20
    • 4,6k
    • 8
    Поделиться публикацией
    Похожие публикации
    Комментарии 8
    • +3
      Во-первых, зачем тут SQL? SQL как язык запросов к базе.

      Имхо, все это намного красивее пишется, если вся страница проектируется в стиле event-driven development. Надо достать определенную сущность? Не вопрос! Генерируем соответствующее событие, а JS реагирующий на событие уже сам понимает нужен ли запрос к серверу или нет. Благодаря этому и синхронизация, и очистка по TTL клиентского кеша, и куча других вещей будут писаться очень просто.
      • +3
        navigator.onLine

        К сожалению, это будет работать только в Opera и Firefox
        У меня в IE8 работает.
      • 0
        нда, наворотили фигни на ровном месте с этими фичами…
        • 0
          Подробнее о создании кэша для оффлайн приложений можно прочитать тут. А на StackOverflow можно почитать дискуссию о том, какой же метод все таки удобнее.

          Не могли бы вы припомнить 2 ссылки, упомянутые в этих предложениях?

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