Как при закрытии браузера автоматически удалять личные данные

Перевод: Влад Мержевич

Постоянное локальное хранилище это одна из областей, где клиентские приложения имеют преимущества перед серверными. Для приложений, таких как операционная система, обеспечивается уровень абстракции для хранения и извлечения данных вроде настроек или статуса выполнения. Эти значения могут быть сохранены в реестре, INI-файлах, XML-файлах или в другом месте в зависимости от принципов платформы. Если ваше клиентское приложение нуждается в локальном хранилище больше чем просто пара ключ/значение, вы можете вставить свою собственную базу данных, придумать свой формат файлов или любое количество других решений.

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

  • кукисы включаются в каждый HTTP-запрос, замедляя тем самым ваше веб-приложение на напрасную передачу одних и тех же данных снова и снова;
  • кукисы включаются в каждый HTTP-запрос при передаче данных через Интернет в незашифрованном виде (даже если все веб-приложение передается через SSL);
  • кукисы ограничены объемом данных примерно 4 Кб - достаточно, чтобы замедлить ваше приложение (см. выше), но не достаточно, чтобы быть полезным.

Вот что мы действительно хотим:

  • много места для хранения;
  • работа на стороне клиента;
  • учитывать обновление страницы;
  • нет отправки на сервер.

Перед HTML5 все попытки добиться этого в конечном итоге были по-разному провальными.

Краткая история локального хранилища до HTML5

Вначале был только один Internet Explorer. По крайней мере, Майкрософт хотел, чтобы мир так думал. С этой целью в рамках Первой Великой Войны браузеров Майкрософт изобрел очень много вещей и включил их в свой браузер-который-завершил-войну - Internet Explorer. Одна из этих вещей была названа DHTML Behaviors , а одна из форм поведения называется userData .

UserData позволяет веб-странице хранить до 64 Кб данных на каждый домен в иерархической XML-подобной структуре. Доверенные домены, такие как интранет-сайты могут хранить в десять раз больше. И эй, 640 Кб должно быть достаточно для всех. IE не представил какой-либо способ изменить эти соглашения, поэтому нет способа увеличить объем доступной памяти.

В 2002 году компания Adobe представила функцию во Flash 6, которая получилась неудачной и с названием, вводящим в заблуждение - «Flash-кукисы». В среде Flash эта возможность известна более правильно как Local Shared Objects (локальные доступные объекты, LSO). Вкратце, она позволяет Flash-объектам хранить до 100 Кб данных на каждый домен. Брэд Нойберг разработавший ранний прототип моста между Flash и JavaScript назвал ее AMASS (AJAX Massive Storage System), но она была ограничена некоторыми причудами Flash-дизайна. К 2006 году с появлением ExternalInterface во Flash 8 доступ к LSO через JavaScript стал на порядок проще и быстрее. Брэд переписал AMASS и интегрировал ее в популярный Dojo Toolkit под псевдонимом dojox.storage . Flash «бесплатно» дает каждому домену 100 кб для хранения. Кроме того, он предлагает пользователю при запросе увеличивать объем хранения на порядок (1 Мб, 10 Мб и т.д.).

if (Modernizr.localstorage) {
// window.localStorage is available!
} else {
// нет встроенной поддержки HTML5-хранилища
}

Использование HTML5-хранилища

HTML5-хранилище базируется на именах пар ключ/значение. Вы сохраняете информацию, основываясь на имени ключа, а затем можете получить эти данные с тем же ключом. Имя ключа это строка. Данные могут быть любого типа, который поддерживает JavaScript, включая строки, логические, целые числа или числа с плавающей запятой. Однако в действительности данные хранятся в виде строки. Если вы сохраняете и извлекаете не строки, то надо будет использовать такие функции как parseInt() или parseFloat() , чтобы перевести полученные данные в корректные типы JavaScript.

Интерфейс хранилища {
Получить через getItem(ключ);
Установить через setItem(ключ, данные);
};

Вызов setItem() с существующим именем ключа молча перепишет предыдущее значение. Вызов getItem() с несуществующим ключом вернет NULL, а не вызовет исключение.

Подобно другим объектам JavaScript вы можете обращаться к объекту localStorage как к ассоциативному массиву. Вместо использования методов getItem() и setItem() , вы можете просто указать квадратные скобки. Например, этот фрагмент кода

var foo = localStorage.getItem("bar");
// ...
localStorage.setItem("bar", foo);

может быть переписан с использованием синтаксиса квадратных скобок:

var foo = localStorage["bar"];
// ...
localStorage["bar"] = foo;

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

Интерфейс хранилища {
Удалить через removeItem(ключ);
clear();
}

Вызов removeItem() с несуществующим ключом ничего не вернет.

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

Интерфейс хранилища {
length
Получить key(целое неотрицательное число);
}

Если при вызове key() индекс лежит не в диапазоне от 0 до (length-1), то функция вернет null .

Слежение за областью HTML5-хранилища

Если вы хотите программно отслеживать изменения хранилища, то должны отлавливать событие storage . Это событие возникает в объекте window , когда setItem() , removeItem() или clear() вызываются и что-то изменяют. Например, если вы установили существующее значение или вызвали clear() когда нет ключей, то событие не сработает, потому что область хранения на самом деле не изменилась.

Событие storage поддерживается везде, где работает объект localStorage , включая Internet Explorer 8. IE 8 не поддерживает стандарт W3C addEventListener (хотя он, наконец-то, будет добавлен в IE 9), поэтому, чтобы отловить событие storage нужно проверить, какой механизм событий поддерживает браузер (если вы уже проделывали это раньше с другими событиями, то можете пропустить этот раздел до конца). Перехват события storage работает так же, как и перехват других событий. Если вы предпочитаете использовать jQuery или какую-либо другую библиотеку JavaScript для регистрации обработчиков событий, то можете проделать это и со storage тоже.

if (window.addEventListener) {
window.addEventListener("storage", handle_storage, false);
} else {
window.attachEvent("onstorage", handle_storage);
};

Функция обратного вызова handle_storage будет вызвана с объектом StorageEvent , за исключением Internet Explorer, где события хранятся в window.event .

function handle_storage(e) {
if (!e) { e = window.event; }
}

В данном случае переменная e будет объектом StorageEvent , который обладает следующими полезными свойствами.

* Примечание: свойство url изначально называлось uri и некоторые браузеры поддерживали это свойство перед изменением спецификации. Для обеспечения максимальной совместимости вы должны проверить существует ли свойство url , и если нет проверить вместо него свойство uri .

Событие storage нельзя отменить, внутри функции обратного вызова handle_storage нет возможности остановить изменение. Это просто способ браузеру сказать вам: «Эй, это только что случилось. Вы ничего не можете сделать, я просто хотел, чтобы вы знали».

Ограничения в текущих браузерах

Говоря об истории локального хранилища с помощью сторонних плагинов, я упомянул про ограничения каждой техники. Я вспомнил, что не сказал ничего об ограничениях теперь уже стандартного HTML5-хранилища. Я дам вам ответы, а затем объясню их. Ответы в порядке важности такие: «5 мегабайт», «QUOTA_EXCEEDED_ERR» и «нет».

«5 мегабайт» - сколько места для хранения выдается по умолчанию. Это значение на удивление одинаково во всех браузерах, хотя и сформулировано не более как предложение в спецификации HTML5. Надо понимать, что вы храните строки, а не данные в исходном формате. Если вы храните много целых чисел или чисел с плавающей запятой, разница в представлении может оказаться большой. Каждая цифра в числе с плавающей запятой хранится в виде символа, а не в обычном представлении для таких чисел.

«QUOTA_EXCEEDED_ERR» это исключение, которое вы получите, если превысите свою квоту в 5 Мб. «Нет» является ответом на следующий очевидный вопрос: «Могу ли я попросить у пользователя больше пространства для хранения?». На момент написания в браузерах не реализован какой-либо механизм для веб-разработчиков, чтобы запросить больше места для хранения. Некоторые браузеры (например, Opera) позволяют пользователю контролировать квоты хранилища для каждого сайта, но это чисто инициатива пользователя, не связанная с тем, что вы как разработчик можете встроить в ваше веб-приложение.

HTML5-хранилище в действии

Давайте посмотрим на HTML5-хранилище в действии. Снова обратимся к , которую мы построили в главе про рисование. С этой игрой связана небольшая проблема: если вы закроете окно браузера посередине игры, то потеряете результаты. Но с HTML5-хранилищем мы можем сохранять процесс игры на месте, в самом браузере. Откройте демонстрацию, сделайте несколько ходов, закройте вкладку браузера, а затем снова ее откройте. Если ваш браузер поддерживает HTML5-хранилище, демонстрационная страница волшебным образом вспомнит точное положение в игре, в том числе, сколько ходов вы сделали, положение каждой фишки на доске и даже выбранную фишку.

Как это работает? Каждый раз, когда происходит изменение в игре, мы будем вызывать эту функцию.

function saveGameState() {

localStorage["halma.game.in.progress"] = gGameInProgress;
for (var i = 0; i < kNumPieces; i++) {
localStorage["halma.piece." + i + ".row"] = gPieces[i].row;
localStorage["halma.piece." + i + ".column"] = gPieces[i].column;
}
localStorage["halma.selectedpiece"] = gSelectedPieceIndex;
localStorage["halma.selectedpiecehasmoved"] = gSelectedPieceHasMoved;
localStorage["halma.movecount"] = gMoveCount;
return true;
}

Как видите, используется объект localStorage для сохранения процесса игры (gGameInProgress , логический тип). Далее перебираются все фишки (gPieces , массив JavaScript) и сохраняется строка и столбец для каждой из них. После чего сохраняются некоторые дополнительные состояния игры, включая выбранную фишку (gSelectedPieceIndex , целое число), фишку, которая находится в середине длинной серии прыжков (gSelectedPieceHasMoved , логический тип) и общее число сделанных ходов (gMoveCount , целое число).

При загрузке страницы вместо автоматического вызова функции newGame() , которая бы вернула все переменные в исходные значения, мы вызываем resumeGame() . Функция resumeGame() с помощью HTML5-хранилища проверяет состояние игры в локальном хранилище. Если оно есть, то восстанавливает значения с использованием объекта localStorage .

function resumeGame() {
if (!supportsLocalStorage()) { return false; }
gGameInProgress = (localStorage["halma.game.in.progress"] == "true");
if (!gGameInProgress) { return false; }
gPieces = new Array(kNumPieces);
for (var i = 0; i < kNumPieces; i++) {
var row = parseInt(localStorage["halma.piece." + i + ".row"]);
var column = parseInt(localStorage["halma.piece." + i + ".column"]);
gPieces[i] = new Cell(row, column);
}
gNumPieces = kNumPieces;
gSelectedPieceIndex = parseInt(localStorage["halma.selectedpiece"]);
gSelectedPieceHasMoved = localStorage["halma.selectedpiecehasmoved"] == "true";
gMoveCount = parseInt(localStorage["halma.movecount"]);
drawBoard();
return true;
}

Наиболее важной частью этой функции является оговорка, о которой я упоминал ранее в этой главе и повторю здесь: данные хранятся в виде строк. Если вы храните нечто другое, а не строки, вам нужно конвертировать их при получении. К примеру, флаг о том, что игра в процессе (gGameInProgress ) является логическим типом. В функции saveGameState() мы просто храним его и не беспокоимся о типе данных.

localStorage["halma.game.in.progress"] = gGameInProgress;

Но в функции resumeGame() мы должны рассмотреть значение, полученное из локального хранилища в виде строки и вручную построить собственное логическое значение.

gGameInProgress = (localStorage["halma.game.in.progress"] == "true");

Аналогичным образом, число ходов хранится в gMoveCount как целое, в функции saveGameState() мы просто сохраняем его.

localStorage["halma.movecount"] = gMoveCount;

Но в функции resumeGame() мы должны конвертировать значение в целое, используя встроенную в JavaScript функцию parseInt() .

gMoveCount = parseInt(localStorage["halma.movecount"]);

За пределами пары ключ/значение: конкурентное видение

Хотя в истории было много уловок и обходных путей, нынешнее состояние HTML5-хранилища на удивление благополучно. Новый API был стандартизирован и включен во все основные браузеры, платформы и устройства. Для веб-разработчика такое увидишь не каждый день, не так ли? Но это больше, чем «5 мегабайт пар ключ/значение» и будущее постоянного локального хранилища это... как бы сказать... ну, пусть конкурентное видение.

Одно видение является аббревиатурой, которую вы уже знаете - SQL. В 2007 году Google запустил Gears, кроссбраузерный плагин с открытым исходным кодом, в который включена встроенная база данных на основе SQLite. Этот ранний прототип позже повлиял на создание спецификации Web SQL Database . База данных Web SQL (ранее известная как «WebDB») обеспечивает тонкую оболочку вокруг базы данных SQL, что позволяет делать следующие вещи из JavaScript:

openDatabase("documents", "1.0", "Local document storage", 5*1024*1024, function (db) {
db.changeVersion("", "1.0", function (t) {
t.executeSql("CREATE TABLE docids (id, name)");
}, error);
});

Как вы можете видеть, большая часть действий находится в строке с методом ExecuteSQL. Эта строка может поддерживать любые команды SQL, в том числе SELECT, UPDATE, INSERT и DELETE. Это все равно, что серверное программирования баз данных, за исключением того, что вы делаете это с JavaScript! О радость!

Спецификация базы данных Web SQL была реализована в четырех браузерах и платформах.

Поддержка базы данных Web SQL
IE Firefox Safari Chrome Opera iPhone Android
4.0+ 4.0+ 10.5+ 3.0+ 2.0+

Конечно, если вы использовали более чем одну базу данных в своей жизни, то знаете, что «SQL» это скорее маркетинговый термин, чем жесткий и быстрый стандарт (кто-то может сказать то же самое об HTML5, но это не важно). Конечно, есть актуальная спецификация SQL (она называется SQL-92), но в мире нет сервера баз данных, который соответствует только этой спецификации. Есть Oracle SQL, Microsoft SQL, SQL в MySQL, SQL в PostgreSQL, SQL в SQLite. В действительности, каждый из этих продуктов с течением времени добавляет новые функции SQL, так что недостаточно даже произнести «SQL в SQLite». Вы должны сказать «версия SQL, который поставляется вместе с SQLite версии X.Y.Z».

Все это подводит нас к следующей оговорке, в настоящее время размещенной вверху спецификации Web SQL.

Спецификация зашла в тупик: все заинтересованные разработчики используют серверный SQL (SQLite), но нам нужно несколько независимых реализаций, чтобы двигаться по пути стандартизации. Пока другие разработчики заинтересованы в реализации этой спецификации, описание диалекта SQL было оставлено как обычная ссылка на Sqlite, который не приемлем для стандарта.

Именно на этом фоне я расскажу вам о другом конкурентном видении для продвинутых, постоянное локальное хранилище для веб-приложений: Indexed Database API , ранее известное как «WebSimpleDB», теперь ласково называемое IndexedDB.

Indexed Database API предоставляет то, что называется хранилище объектов, при этом много идей заимствовано из баз данных SQL. Есть «базы данных» с «записями», каждая запись имеет определенное количество «полей». У каждого поля есть определенный тип данных, который определяется при создании базы данных. Вы можете выбрать часть записей, затем перечислить их «курсором». Изменения в хранилище объектов обрабатываются с «транзакциями».

Если вы хоть раз программировали базы данных SQL, то эти термины, вероятно, вам знакомы. Основная разница в том, что хранилище объектов не имеет структурированного языка запросов. Вы не напишите условие вроде "SELECT * from USERS where ACTIVE = "Y"". Вместо этого используются методы, предоставляемые хранилищем объектов для открытия базы USERS, перечисления записей, фильтрации наших записей и использование методов доступа для получения значения каждого поля оставшихся записей. An early walk-through of IndexedDB (Ранний проход IndexedDB) это хорошее руководство о том, как работает IndexedDB и сравнение IndexedDB с Web SQL.

На момент написания IndexedDB был реализован только в бета-версии Firefox 4. Для контраста, Mozilla заявила, что никогда не будет воплощать Web SQL. Google заявил, что они рассматривают поддержку IndexedDB для Chromium и Google Chrome. И даже Майкрософт заявил, что IndexedDB «отличное решение для веб».

Что вы как веб-разработчик можете делать с IndexedDB? На данный момент практически ничего, кроме некоторых технологических демонстраций. Через год? Возможно.

Использование возможностей HTML5 для сохранения данных и оффлайновой работы

Часть 1. Реализация оффлайнового редактирования данных и синхронизации данных

Серия контента:

Этот контент является частью # из серии # статей: Использование возможностей HTML5 для сохранения данных и оффлайновой работы

http://www.?sn=dw&lang=ru&cc=RU&en=utf&hpp=20&dws=rudw&lo=ru&q=%D0%98%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5+%D0%B2%D0%BE%D0%B7%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D0%B5%D0%B9+HTML5+%D0%B4%D0%BB%D1%8F+%D1%81%D0%BE%D1%85%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F+%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85+%D0%B8+%D0%BE%D1%84%D1%84%D0%BB%D0%B0%D0%B9%D0%BD%D0%BE%D0%B2%D0%BE%D0%B9+%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%8B&Search=%D0%9F%D0%BE%D0%B8%D1%81%D0%BA

Следите за выходом новых статей этой серии.

Согласно существующим планам, технология HTML5 (HTML version 5) получит статус Рекомендации организации World Wide Web Consortium (W3C) не ранее 2014 года. Хотя технология HTML5 еще не является официальным стандартом, поставщики веб-браузеров уже добавляют и продвигают HTML5-функции. Технология HTML5 расширяет веб-возможности для сайтов в Интернете и для бизнес-приложений. Многие веб-сайты, такие как Amazon Kindle Cloud Reader, уже используют технологию HTML5. Следующие две ключевые функции HTML5 существенно изменят бизнес-приложения: поддержка оффлайновых приложений и локальное персистентное хранилище. Поскольку технология HTML5 не является официальным стандартом, ее поддержка различными браузерами в лучшем случае не единообразна.

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

Учебное приложение

Учебное приложение Contact Manager обеспечивает управление контактной информацией (имена, адреса, номера телефонов). Оно поддерживает онлайновый режим, оффлайновый режим и простую функцию синхронизации данных, которая позволяет синхронизировать локальные изменения данных с сервером после переключения на онлайновый режим. При нахождении приложения в оффлайновом режиме данные размещаются в локальном персистентном хранилище. Описываемое приложение поддерживает четыре базовые функции персистентного хранения — создание/чтение/обновление/удаление (create/read/update/delete, CRUD) — и в онлайновом, и в оффлайновом режимах.

Архитектура

Модель данных

Модель данных состоит из двух объектов данных, contact и state (см. ). Таблица contact содержит фактические контактные сведения; таблица state содержит значения словаря для списка выбора состояния.

Рисунок 2. Модель данных

Интерфейс сервера

Интерфейс сервера состоит из двух сервлетов: ContactServlet и DictionaryServlet . Эти сервлеты описаны в (реализация этих сервлетов, а также соответствующих бизнес-сервисов и провайдеров данных, выходит за рамки этой статьи).

Таблица 1. Описание сервлетов
Имя сервлета Операция Параметры Описание
DictionaryServlet code> getstates Отсутствуют Возвращает массив состояний в формате JSON (JavaScript Object Notation).
ContactServlet getallcontacts Отсутствуют Возвращает массив записей контактов в формате JSON.
ContactServlet delete contactId - Идентификатор (ID) контакта, подлежащего удалению. Удаляет указанную запись контакта; возвращает JSON-объект с логическим флагом, который служит индикатором успешности операции.
"{"result": true/false"}
ContactServlet save
  • contactId - Идентификатор (ID) контакта, подлежащего сохранению (если значение больше нуля, то имеет место операция обновления).
  • firstName - Значение поля name.
  • lastName - Значение поля last name.
  • street1 - Значение поля street 1.
  • street2 - Значение поля street 2.
  • city - Значение поля city.
  • state - Значение поля state.
  • zipCode - Значение поля zipCode.
Возвращает JSON-объект с логическим флагом, который служит индикатором успешности операции, и новый или обновленный идентификатор контакта.
"{"contactId": , "result": "}

Вызов интерфейса сервера

Рисунок 3. Приложение Contact Manager

JavaScript-модули

Приложение состоит из четырех специальных JavaScript-модулей:

  • core.js – поддерживает обычные функции JavaScript и используется другими модулями.
  • formEvents.js – предоставляет обработчиков событий для кнопок и форм. Он направляет операции базы данных к надлежащему провайдеру данных в соответствии с онлайновым или оффлайновым режимом.
  • onlinedb.js – поддерживает функции для взаимодействия с сервером при нахождении в онлайновом режиме.
  • offlinedb.js поддерживает функции для локального хранения данных.

Кроме того, все модули используют последнюю версию библиотеки jQuery для прослеживания данных, для асинхронных веб-запросов и для поддержки dynamic HTML. Клиент взаимодействует с сервером с помощью JSON.

Манифест оффлайнового приложения

Оффлайновые возможности HTML5 обеспечивают кэширование статических файлов и ресурсов. Файл манифеста оффлайнового приложения (.appcache) – это важнейший файл для поддержки оффлайнового приложения для веб-приложения. Файл манифеста содержит следующую информацию.

  • Ресурсы и страницы, доступные в оффлайновом режиме.
  • Ресурсы, доступные только в онлайновом режиме.
  • Для ресурсов, которые не доступны в оффлайновом режиме, отображается fallback-страница.

Файл манифеста состоит из трех разделов: CACHE, NETWORK, FALLBACK . Страницы и ресурсы, перечисленные в разделе CACHE , кэшируются на локальной системе. Страницы и ресурсы, перечисленные в разделе NETWORK , никогда не кэшируются и доступны только в онлайновом режиме. Страница, указанная в разделе FALLBACK , отображается, если требуемая страница недоступна в оффлайновом режиме. Символ (*) в разделе NETWORK указывает, что все остальные страницы и сервлеты доступны только в онлайновом режиме. Если символ (*) отсутствует, вызовы сервлета окажутся неудачными (даже в онлайновом режиме). В показан файл манифеста для приложения Contact Manager.

Листинг 8. Манифест оффлайнового приложения
CACHE MANIFEST # Revision 1 CACHE: default.html list.html scripts/core.js scripts/localdb.js scripts/onlinedb.js scripts/formEvents.js http://code.jquery.com/jquery-1.7.2.min.js NETWORK: * FALLBACK: / offline.html

Важная информация для работы с оффлайновыми приложениями.

  • Расширение файла манифеста оффлайнового приложения.appcache должно быть отображено на MIME-тип text/cache-manifest . В среде Apache Tomcat эта задача решается посредством добавления элемента mime-mapping в файл web.xml сервера (а не в файл web.xml веб-приложения). Большинство браузеров молча игнорирует манифест оффлайнового приложения, если его MIME-тип является некорректным.
  • Если файл манифеста оффлайнового приложения присутствует, всегда используется ресурс, кэшированный на локальной системе (даже при нахождении в онлайновом режиме).
  • Локальный ресурс обновляется только в том случае, если изменяется файл манифеста оффлайнового приложения; как правило, посредством изменения номера версии в комментариях внутри файла манифеста. Изменения HTML-ресурсов или CSS-ресурсов не отражаются в веб-браузере до тех пор, пока файл манифеста приложения не будет изменен.
  • Каждая страница, поддерживающая оффлайновое использование, должна иметь следующую строку:

Онлайновое или оффлайновое приложение

JavaScript позволяет обнаружить, является ли приложение онлайновым или оффлайновым. Эта задача решается с помощью логической переменной navigator.onLine . Если приложение является онлайновым, то эта переменная возвращает значение True.

События форм (обработка в онлайновом и в оффлайновом режиме)

В приложении Contact Manager одна и та же форма используется и в онлайновом, и в оффлайновом режиме. Чтобы это решение работало, необходимы обработчики событий форм и кнопок. Проверьте значение переменной navigator.onLine с целью определения того, какую операцию следует вызвать (локальную или онлайновую). В показан пример для загрузки контактных данных.

Листинг 9. Загрузка данных (в событии onLoad)
if (navigator.onLine) { // selection list needs to be populated prior to synchronizing data // the list is updated from the online dictionary later populateOfflineStates(); setStatusText("Synchronizing contact data with server..."); synchronizeContacts(); setStatusText("Loading dictionary data from server..."); populateOnlineStates(); setStatusText("Loading contact data from server..."); loadOnlineContacts(); } else { alert("You are currently offline."); populateOfflineStates(); setStatusText("Loading contact data from local storage..."); loadOfflineContacts(); }

Синхронизация данных

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

В оффлайновом режиме все CRUD-операции для сохранения изменений используют локального провайдера данных. После восстановления соединения с сервером производятся следующие действия.

  • Все записи, которые были созданы на локальной системе, сохраняются на сервере.
  • Все записи, которые были изменены на локальной системе, обновляются на сервере.
  • Все записи, которые были удалены на локальной системе, удаляются на сервере.

Полный текст метода синхронизации показан в . В процессе синхронизации одни и те же онлайновые функции используются для операций создания, обновления и удаления. Первый шаг состоит в итеративном прохождении по локальным записям с помощью jQuery-функции $.each .

Записи, которые были обновлены или созданы на локальной системе, помечаются с помощью свойства isDirty . Операция Save (сохранить) идентифицируется как новая, если ее уникальный идентификатор записи имеет отрицательное значение (т.е. база данных MySQL не присвоила ему какого-либо значения). Записи, которые были удалены на локальной системе, помечаются с помощью свойства isDeleted .

Листинг 10. Синхронизация оффлайновых изменений с сервером
var recordsUpdated = 0; var recordsCreated = 0; var recordsDeleted = 0; $.each(data, function(i,item){ if (item.isDeleted) { deleteOnlineContact(item.id, true); recordsDeleted++; } else if (item.isDirty && !item.isDeleted) { $("input").value = item.id; $("input").value = item.firstName; $("input").value = item.lastName; $("input").value = item.street1; $("input").value = item.street2; $("input").value = item.city; $("select").value = item.state; $("input").value = item.zipCode; var dataString = $("#editContactForm").serialize(); postEditedContact(dataString, true); if (item.id > 0) { recordsUpdated++; } else { recordsCreated++; } } }); var msg = "Synchronization Summary\n\tRecords Updated: " + recordsUpdated + "\n\tRecords Created: " + recordsCreated +"\n\tRecords Deleted: " + recordsDeleted; alert(msg);

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

Заключение

На примере учебного приложения в статье были продемонстрированы рекомендации по поддержке онлайнового и оффлайнового режимов работы. Единообразные пользовательские возможности обеспечиваются посредством использования одной и той же HTML-страницы для онлайнового и оффлайнового режимов, а также посредством вызова надлежащих онлайновых/оффлайновых провайдеров данных в обработчиках событий форм в соответствии с текущим состоянием (онлайновым или оффлайновым).

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

Создание приложения “список дел” (амер. to-do list), обычно, является первым приложением, которое вы делаете при изучении JavaScript, но проблема всех этих приложений является в том, что, когда вы перезагружаете страницу все эти списки исчезают.
Существует простое решение - использование локального хранилища. Преимуществом локального хранилища является то, что вы можете сохранить биты данных на компьютере пользователя, и когда произошла перезагрузка страницы, все списки задач остались на месте.

Что такое локальное хранилище?

Локальное хранение данных является частью сети хранения, которое само по себе является частью спецификации HTML5. Есть два варианта для хранения данных в спецификации:

  • Локальное хранилище (Local Storage): хранит данные без даты окончания срока действия, и это тот вариант, который мы будем использовать, потому что мы хотим, чтобы наши списки оставались на странице как можно дольше.
  • Хранение сессии (Session Storage): только сохраняет данные в течение одной сессии, так что если пользователь закрывает вкладку и вновь открывает её, все его данные будут потеряны.

Простыми словами, все, что веб хранилище делает, это сохраняет key/value пары с именем локально, и в отличие от cookies, эти данные сохраняются даже если вы закроете браузер или выключите компьютер.

Если мы думаете о списке дел, то вам понадобится следующие:

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

Таким образом, наш HTML должен выглядеть примерно так:

Это довольно стандартный HTML контейнер, и с нашими JavaScript мы можем заполнить все это с динамическим контентом.

Так как мы будем использовать JQuery в этом примере, вы также должны включить его в HTML документ.

JavaScript

Если мы подумаем о структуре простого “to-do list” приложения, то первое что нам нужно сделать, это проверить, имеет ли ввод пустое значениее, когда пользователь нажимает на кнопку “добавить” или “проверить”:

$("#add").click(function() { var Description = $("#description").val(); //if the to-do is empty if($("#description").val() == "") { $("#alert").html("Warning! You left the to-do empty"); $("#alert").fadeIn().delay(1000).fadeOut(); return false; }

Все, что мы сделали, это проверили клик по кнопке Добавить и запустили простой тест, чтобы проверить, если пользователь заполнил ввод чем-то. Если нет, то тогда предупреждение div всплывает и остается на 1000 мс, а затем исчезает.

Следующее, что нам нужно сделать, это вставить элемент списка со значением в cтроку ввода, и мы предварим это так, что, когда пользователь добавляет задачу, она всегда будет идти в начало списка, а затем сохранять элемент списка в локальное хранилище, вот так:

// add the list item $("#todos").prepend("

  • " + Description + "
  • "); // delete whatever is in the input $("#form").reset(); var todos = $("#todos").html(); localStorage.setItem("todos", todos); return false; });

    Как вы видите, это довольно стандартный jQuery и когда дело доходит до локального хранилища мы должны сохранить ключ и значение. Ключ представляет собой имя, которое мы себе задаем, в этом случае мы просто назовем его «Todos”, затем мы должны определить, что мы хотим сохранить, и в данном случае это весь HTML, что находится внутри Todos неупорядоченного списка. Как вы видите, мы все захватили с помощью jQuery, и наконец, вернули “ложные” (false) так, чтобы форма не сдавалась и наша страница не обновлялась.

    Наш следующий шаг, это проверить, есть ли у нас что-то сохраненное на локальном хранилище. Если есть, то тогда нам нужно разместить это на странице, учитывая то, что мы дали нашему ключу имя “todos”, нам нужно проверить его существование. Вот так:

    // if we have something on local storage place that if(localStorage.getItem("todos")) { $("#todos").html(localStorage.getItem("todos")); }

    Если вы протестируете наше приложение и перезагрузите страницу, то увидите, что она уже работает. Все, что нам остаеться сделать, это создать функцию, которая будет отвечать за очистку всего списка. Мы стираем все местные хранения, перезагружаем страницу, чтобы наше изменение вступило в силу, а затем возвращаем “false”, чтобы предотвратить хэш перед URL следующим образом:

    // clear all the local storage $("#clear").click(function() { window.localStorage.clear(); location.reload(); return false; });

    Полный код выглядит следующим образом:

    $("#add").click(function() { var Description = $("#description").val(); if($("#description").val() == "") { $("#alert").html("Warning! You left the to-do empty"); $("#alert").fadeIn().delay(1000).fadeOut(); return false; } $("#todos").prepend("

  • " + Description + "
  • "); $("#form").reset(); var todos = $("#todos").html(); localStorage.setItem("todos", todos); return false; }); if(localStorage.getItem("todos")) { $("#todos").html(localStorage.getItem("todos")); } $("#clear").click(function() { window.localStorage.clear(); location.reload(); return false; });

    Поддержка браузеров

    Поддержка Web Storage довольно хороша для HTML5 спецификаций, он поддерживается всеми основными браузерами и даже IE8.

    last edited by

    Здравствуйте.

    Давно замечаю, что не работает опция "Хранить локальные данные до выхода из браузера", что в разделе "Файлы cookie" настроек безопасности Опера. То удаляет cookie, то нет, как-то случайно.

    Проверяется легко. Ставим вышеупомянутый флаг. Используем Опера пару дней. Отключаем Интернет. Запускаем Опера. Открываем список cookie и видим в нем не удаленные записи! Очистка cookie в приказном порядке - работает, автоматическая - хрен! То бишь, вся анонимность летит к чертям. Естественно, VPN теряет смысл.

    Кто-то может что сказать по этому поводу?

    P. S. У меня сложилось мнение, что Опера стараются угробить. Прогресса не чувствуется.

  • Были такие же проблемы раньше у других пользователей. Почитайте...

    Почитал. Благодарю. Советуют установить надстройку. Сразу нашел в ней ошибку: не очищает историю загрузок, хотя опция такая есть. Я конечно не буду использовать непонятную надстройку, когда дело касается безопасности.

    Думал, может влияют какие-то другие флаги. Так как назначение и работа многих флагов мне непонятны. Например "Разрешать недавно закрытым сайтам завершить прием и передачу данных".

    Надеюсь, проблему с удалением cookie решат. На сколько я заметил, она тянется еще с Опера 12.

  • уже нашли причину этой проблемы. Все винили браузер Opera, а оказалось это баг самого Chromium....

    Вот и я думаю на Опера Так как у меня стоит для тестов Опера 12 и там та же хрень.

    Странно видеть такие ошибки в 50-й то версии.

    Что там внутри у Опера конечно интересно. Но продукт называется Опера, а не Chromium или еще как

  • operasilver40 last edited by

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

    Если вы приверженец конфиденциальности и каждый раз по окончании работы в интернете очищаете личные данные вручную, то знайте, эту функцию браузер может выполнять в автоматическом. Как только вы нажмёте кнопку выход, браузер за вас сделает всю эту работу. Обратите внимание, если вы настроите свой браузер, согласно этому руководству, будут очищены файлы cookies. Это означает, что вам придётся заново авторизовываться на тех веб-сайтах, на которых вы зарегистрированы. Так же очистка кэш-файлов вызовет более медленную загрузку веб-страниц после перезапуска браузера.

    Google Chrome

    Google Chrome не включает в настройки возможность автоматического удаления ваших личных данных, когда вы закрываете его. Тем не менее есть возможность настроить браузер на автоматическое очищение при выходе. Для этого необходимо установить и использовать расширение, но об этом чуть позже. Для начала, откройте настройки в меню Chrome, в самом низу страницы нажмите Показать дополнительные настройки , графа Личные данные , нажмите кнопку Настройки контента . В открывшемся блоке в графе Файлы cookie установите Удалять локальные данные при закрытии браузера и нажмите кнопку Готово .


    Теперь при закрытии Chrome, браузер будет автоматически очищать файлы cookie.

    Чтобы браузер очищал все ваши личные данные, при закрытии, вы должны установить расширение Click&Clean в Интернет магазине Chrome.

    Описание расширения: Click&Clean поможет вам удалить историю посещений и загрузок, очистить кэш, ускорить работу Хрома и освободить место на вашем жестком диске!
    Простое и эффективное решение для чистки вашего ПК: Очищает историю просмотров, очищает историю загрузок, удаляет файлы cookie, очищает кэш, удаляет Silverlight cookie, удаляет Flash LSO файлы, очищает кэш Java и многое другое. После его установки, нажмите кнопку Click&Clean на панели инструментов браузера и выберите Настройки.

    Включить « Запускать очистку при закрытии Хрома » в разделе Дополнительно.


    Вы можете контролировать, какие типы данных будут автоматически удалены с помощью параметров в этом окне.

    Mozilla Firefox

    Firefox обладает встроенной способностью очищать все ваши личные данные, когда вы закрываете его, расширений не требуется. Хотя если вы посмотрите на изображение выше, расширение Click&Clean в заголовке имеет ссылку Get for Firefox! на прямую установку расширения в браузер. Если вы нажмёте на ссылку, автоматически запустится браузер Firefox и установит расширение. Но если вы противник расширений то настройте браузер собственными средствами. Откройте настройки Firefox. Перейдите на вкладку Приватность и выберите « Будет использовать ваши настройки хранения истории . Установите флажок Удалять историю при закрытии Firefox .


    Вы можете контролировать, какие типы личных данных Firefox автоматически очистит, нажмите на кнопку Параметры .


    Выберите, что при закрытии браузера вы хотите очистить а что оставить как есть.

    Internet Explorer

    Internet Explorer так же обладает встроенной способностью очищать ваши личные данные, когда вы его закрываете. Нажмите Сервис и выберите Свойства обозревателя , чтобы начать настройки. На вкладке Общие в графе Журнал браузера включите опцию « Удалять журнал браузера при выходе «. Настроить, какие типы данных Internet Explorer будет очищать при выходе, нажмите кнопку Удалить .

    Например вы можете снять флажок « Сохранять данные избранных веб-сайтов » и тогда Internet Explorer не будет очищать фалы cookie и файлы кэша для веб-сайтов, сохраненных в качестве избранных. Нажмите кнопку Удалить , когда вы закончите настройки. Internet Explorer немедленно запустит механизм очистки. Теперь браузер будет очищать личные данные при закрытии браузера.

    Opera

    Opera как всегда не такая как все. Она не включает в себя функции, которые могут автоматически удалять все ваши личные данные, когда закрывается браузер. Для этого Opera использует механизм под названием Приватный просмотр. Для просмотра страниц в этом режиме в меню Opera выберите пункт Создать приватное окно или Ctrl+Shift+N .

    Приватный просмотр означает, что в истории все сведения о вашей сетевой активности будут удалены сразу после закрытия окна. Когда вы закроете это окно и все связанные с ним вкладки, браузер Opera удалит все связанные с ними данные: Историю просмотров, Элементы в кэше, Cookies. Закрытое приватное окно невозможно восстановить из списка «Недавно закрытые» в главном меню. После использования приватных окон не сохраняется никакой информации о сайтах, которые вы посетили, однако если вы хотите специально сохранить какие-то данные, есть функция «Копилка».


    Если вы сохраните пароль или загрузите файл, то эти элементы будут доступны и после закрытия окна.
    Примечание! Обратите внимание, что Opera не очистит те файлы cookies которые уже есть. Чтобы очистить их, используйте Все cookies и данные сайта.


    Откройте в меню Настройки , перейдите на вкладку Конфиденциальность и безопасность . В графе Cookies установите Хранить локальные данные до выхода из браузера . Нажмите Все cookies и данные сайта , удалите Cookies.


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

    Http://webdoker.ru