Storage
Содержание:
- Курсоры
- Configuration
- isSupported
- Overview #
- За пределами пары ключ/значение: конкурентное видение
- Overview of web storage
- Usage
- Слежение за областью HTML5-хранилища
- The JavaScript localStorage object
- What is the Web Storage API?
- Краткая история локального хранилища до HTML5
- The localStorage Object
- Приватный просмотр (режим инкогнито)
- Storages
Курсоры
Такие методы как возвращают массив ключей/значений.
Но хранилище объектов может быть огромным, больше, чем доступно памяти.
Тогда метод вернёт ошибку при попытке получить все записи в массиве.
Что делать?
Курсоры предоставляют возможности для работы в таких ситуациях.
Объект cursor идёт по хранилищу объектов с заданным запросом (query) и возвращает пары ключ/значение по очереди, а не все сразу. Это позволяет экономить память.
Так как хранилище объектов внутренне отсортировано по ключу, курсор проходит по хранилищу в порядке хранения ключей (по возрастанию по умолчанию).
Синтаксис:
- ключ или диапазон ключей, как для .
-
необязательный аргумент, доступные значения:
- – по умолчанию, курсор будет проходить от самого маленького ключа к большему.
- – обратный порядок: от самого большого ключа к меньшему.
- , – то же самое, но курсор пропускает записи с тем же ключом, что уже был (только для курсоров по индексам, например, для нескольких книг с price=5, будет возвращена только первая).
Основным отличием курсора является то, что генерируется многократно: один раз для каждого результата.
Вот пример того, как использовать курсор:
Основные методы курсора:
- – продвинуть курсор на позиций, пропустив значения.
- – продвинуть курсор к следующему значению в диапазоне соответствия (или до позиции сразу после ключа key, если указан).
Независимо от того, есть ли ещё значения, соответствующие курсору или нет – вызывается , затем в мы можем получить курсор, указывающий на следующую запись или равный .
В приведённом выше примере курсор был создан для хранилища объектов.
Но мы также можем создать курсор для индексов. Как мы помним, индексы позволяют искать по полю объекта. Курсоры для индексов работают так же, как для хранилищ объектов – они позволяют экономить память, возвращая одно значение в единицу времени.
Для курсоров по индексам является ключом индекса (например price), нам следует использовать свойство как ключ объекта:
Configuration
setPrefix
You could set a prefix to avoid overwriting any local storage variables from the rest of your appDefault prefix:
myApp.config(function (localStorageServiceProvider) { localStorageServiceProvider .setPrefix('yourAppName'); });
setStorageType
You could change web storage type to localStorage or sessionStorageDefault storage:
myApp.config(function (localStorageServiceProvider) { localStorageServiceProvider .setStorageType('sessionStorage'); });
setDefaultToCookie
If localStorage is not supported, the library will default to cookies instead. This behavior can be disabled.Default:
myApp.config(function (localStorageServiceProvider) { localStorageServiceProvider .setDefaultToCookie(false); });
setStorageCookie
Set cookie options (usually in case of fallback)expiry: number of days before cookies expire (0 = session cookie). default: path: the web path the cookie represents. default: secure: whether to store cookies as secure. default:
myApp.config(function (localStorageServiceProvider) { localStorageServiceProvider .setStorageCookie(45, '<path>', false); });
setStorageCookieDomain
Set the cookie domain, since this runs inside a the block, only providers and constants can be injected. As a result, service can’t be used here, use a hardcoded string or .No default value
myApp.config(function (localStorageServiceProvider) { localStorageServiceProvider .setStorageCookieDomain('<domain>'); });
For local testing (when you are testing on localhost) set the domain to an empty string ». Setting the domain to ‘localhost’ will not work on all browsers (eg. Chrome) since some browsers only allow you to set domain cookies for registry controlled domains, i.e. something ending in .com or so, but not IPs or intranet hostnames like localhost.
setNotify
Configure whether events should be broadcasted on $rootScope for each of the following actions:setItem , default: , event «LocalStorageModule.notification.setitem»removeItem , default: , event «LocalStorageModule.notification.removeitem»
myApp.config(function (localStorageServiceProvider) { localStorageServiceProvider .setNotify(true, true); });
Configuration Example
Using all together
myApp.config(function (localStorageServiceProvider) { localStorageServiceProvider .setPrefix('myApp') .setStorageType('sessionStorage') .setNotify(true, true) });
isSupported
Checks if the browser support the current storage type(e.g: , ).
Returns:
myApp.controller('MainCtrl', function($scope, localStorageService) { //... if(localStorageService.isSupported) { //... } //... });
setPrefix
Change the local storage prefix during execution
Returns:
myApp.controller('MainCtrl', function($scope, localStorageService) { //... localStorageService.setPrefix('newPrefix'); //... });
getStorageType
Returns:
You can also dynamically change storage type by passing the storage type as the last parameter for any of the API calls. For example:
set
Directly adds a value to local storage.
If local storage is not supported, use cookies instead.Returns:
myApp.controller('MainCtrl', function($scope, localStorageService) { //... function submit(key, val) { return localStorageService.set(key, val); } //... });
get
Directly get a value from local storage.
If local storage is not supported, use cookies instead.Returns:
myApp.controller('MainCtrl', function($scope, localStorageService) { //... function getItem(key) { return localStorageService.get(key); } //... });
keys
Return array of keys for local storage, ignore keys that not owned.Returns:
myApp.controller('MainCtrl', function($scope, localStorageService) { //... var lsKeys = localStorageService.keys(); //... });
remove
Remove an item(s) from local storage by key.
If local storage is not supported, use cookies instead.Returns:
myApp.controller('MainCtrl', function($scope, localStorageService) { //... function removeItem(key) { return localStorageService.remove(key); } //... function removeItems(key1, key2, key3) { return localStorageService.remove(key1, key2, key3); } });
clearAll
Remove all data for this app from local storage.
If local storage is not supported, use cookies instead.Note: Optionally takes a regular expression string and removes matching.Returns:
myApp.controller('MainCtrl', function($scope, localStorageService) { //... function clearNumbers(key) { return localStorageService.clearAll(^\d+$); } //... function clearAll() { return localStorageService.clearAll(); } });
bind
Bind $scope key to localStorageService.
Usage:
key: The corresponding key used in local storage
Returns: deregistration function for this listener.
myApp.controller('MainCtrl', function($scope, localStorageService) { //... localStorageService.set('property', 'oldValue'); $scope.unbind = localStorageService.bind($scope, 'property'); //Test Changes $scope.update = function(val) { $scope.property = val; $timeout(function() { alert("localStorage value: " + localStorageService.get('property')); }); } //... });
<div ng-controller="MainCtrl"> <p>`property`</p> <input type="text" ng-model="lsValue"/> <button ng-click="update(lsValue)">update</button> <button ng-click="unbind()">unbind</button> </div>
deriveKey
Return the derive key
Returns
myApp.controller('MainCtrl', function($scope, localStorageService) { //... localStorageService.set('property', 'oldValue'); //Test Result console.log(localStorageService.deriveKey('property')); // ls.property //... });
length
Return localStorageService.length, ignore keys that not owned.
Returns
myApp.controller('MainCtrl', function($scope, localStorageService) { //... var lsLength = localStorageService.length(); // e.g: 7 //... });
Overview #
This API has been optimized to meet the specific storage needs of extensions. It provides the same storage capabilities as the localStorage API with the following key differences:
- User data can be automatically synced with Chrome sync (using ).
- Your extension’s content scripts can directly access user data without the need for a background page.
- A user’s extension settings can be persisted even when using split incognito behavior.
- It’s asynchronous with bulk read and write operations, and therefore faster than the blocking and serial .
- User data can be stored as objects (the stores data in strings).
- Enterprise policies configured by the administrator for the extension can be read (using with a schema).
За пределами пары ключ/значение: конкурентное видение
Хотя в истории было много уловок и обходных путей, нынешнее состояние 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 была реализована в четырех браузерах и платформах.
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.
Именно на этом фоне я расскажу вам о другом конкурентном видении для продвинутых, постоянное локальное хранилище для веб-приложений: 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? На данный момент практически ничего, кроме некоторых технологических демонстраций. Через год? Возможно.
Overview of web storage
Web storage is data stored locally in a user’s browser. There are two types of web storage:
- Local storage — data with no expiration date that will persist after the browser window is closed.
- Session storage — data that gets cleared after the browser window is closed.
This is useful for saving data such as user preferences (light or dark color theme on a website), remembering shopping cart items, or remembering a user is logged into a website.
Previously, cookies were the only option for remembering this type of local, temporary data. Local storage has a significantly higher storage limit (5MB vs 4KB) and doesn’t get sent with every HTTP request, so it can be a better option for client-side storage.
Here is an overview of methods.
Method | Description |
---|---|
Add key and value to local storage | |
Retrieve a value by the key | |
Remove an item by key | |
Clear all storage |
You can test out what’s in local storage by going to the JavaScript console and typing it in. Actually do this, don’t just read it.
Adding some data to is as easy as using the method. I’ll use a generic key and value for the names, but they can be any strings.
Now if you test in the console again, you’ll find your new key and value.
If you want to get the value for a particular key, you’ll use the method.
Finally, you can remove the data with .
Using will clear all local storage.
Now we can begin setting up the app.
Usage
unless localStorage?{LocalStorage} =require('')localStorage =newLocalStorage('./scratch')localStorage.setItem('myFirstKey', 'myFirstValue')console.log(localStorage.getItem('myFirstKey'))localStorage._deleteLocation()
Open or create and add these two lines:
// /src/setupTests.jsimport { LocalStorage } from "node-localstorage";global.localStorage = new LocalStorage('./scratch');
if (typeof localStorage === "undefined" || localStorage === null) { var LocalStorage = require('node-localstorage').LocalStorage; localStorage = new LocalStorage('./scratch');}localStorage.setItem('myFirstKey', 'myFirstValue');console.log(localStorage.getItem('myFirstKey'));
Polyfil your node.js environment with this as the global localStorage when launching your own code
node -r node-localstorage/register my-code.js
Слежение за областью 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, который обладает следующими полезными свойствами.
Свойство | Тип | Описание |
---|---|---|
key | string | Ключ может быть добавлен, удален или изменен. |
oldValue | любой | Предыдущее значение (если переписано) или null, если добавлено новое значение. |
newValue | любой | Новое значение или null, если удалено. |
url* | string | Страница, которая вызывает метод, приведший к изменению. |
* Примечание: свойство url изначально называлось uri и некоторые браузеры поддерживали это свойство перед изменением спецификации. Для обеспечения максимальной совместимости вы должны проверить существует ли свойство url, и если нет проверить вместо него свойство uri.
Событие storage нельзя отменить, внутри функции обратного вызова handle_storage нет возможности остановить изменение. Это просто способ браузеру сказать вам: «Эй, это только что случилось. Вы ничего не можете сделать, я просто хотел, чтобы вы знали».
The JavaScript localStorage object
HTML5 specification introduces the as a way to store data with no expiration date in the web browsers.
In other words, the data stored in the browsers will persist even after you close the browser windows.
The data stored in the is bound to an origin. It means that the is unique per .
First, the data stored in the isn’t sent to the server in every request like cookies. For this reason, you can store more data in the .
Most modern web browsers allow you to store up to 5MB of data in the . Note that you can store up to 4KB in cookies.
Second, the data stored in the can be managed by the client, specifically JavaScript in the web browser. It cannot be accessible by the servers.
However, cookies can be managed by both JavaScript in web browsers and servers.
Accessing the localStorage
You can access the via the property of the object:
Since the is an instance of the type, you can invoke the methods of the type to manage data.
When you type the following code in the Console:
… you’lll see the following object:
1) The setItem() method
The following uses the method to store a name-value pair in the :
2) The length property
To get the number of name-value pairs, you use the property like this:
Since the object is global, you don’t need to explicitly specify it. For example:
3) The getItem() method
To get the value by a key, you use the method. The following example uses the method to get the value of key:
4) The removeItem() method
To remove a name-value pair by a key, you use the method. For example:
5) Loop over keys of the localStorage object
The following stores three name-value pairs to the :
To iterate over name-value pairs stored in the , you use the method with loop:
Output:
What is the Web Storage API?
The Web Storage API is a set of mechanisms that enable browsers to store key-value pairs. It is designed to be much more intuitive than using cookies.
The key-value pairs represent storage objects, which are similar to objects except they remain intact during page loads, and are always strings. You can access these values like an object or using the method (more on that later).
What is the difference between and ?
The Web Storage API consists of two mechanisms: and . Both and maintain a separate storage area for each available origin for the duration of the page session.
The main difference between and is that only maintains a storage area while the browser is open (including when the page reloads or restores) while continues to store data after the browser is closed. In other words, whereas data stored in is cleared when the page is closed, data stored in does not expire.
In this tutorial, we’ll focus on how to use in JavaScript.
Краткая история локального хранилища до HTML5
Вначале был только один Internet Explorer. По крайней мере, Майкрософт хотел, чтобы мир так думал. С этой целью в рамках Первой Великой Войны браузеров Майкрософт изобрел очень много вещей и включил их в свой браузер-который-завершил-войну — Internet Explorer. Одна из этих вещей была названа DHTML Behaviors, а одна из форм поведения называется userData.
UserData позволяет веб-странице хранить до 64 Кб данных на каждый домен в иерархической XML-подобной структуре. Доверенные домены, такие как интранет-сайты могут хранить в десять раз больше. И эй, 640 Кб должно быть достаточно для всех. IE не представил какой-либо способ изменить эти соглашения, поэтому нет способа увеличить объем доступной памяти.
В 2007 году Google запустила Gears, открытый плагин для браузера направленный на обеспечение дополнительных возможностей. Мы уже обсуждали Gears ранее в контексте обеспечения геолокации в Internet Explorer. Gears предоставляет API для встроенной базы данных на основе SQLite. После получения единственного разрешения от пользователя, Gears может хранить неограниченное количество данных для каждого домена в таблицах базы данных SQL.
В то же время Брэд Нойберг и другие продолжали вкалывать на dojox.storage чтобы обеспечить единый интерфейс для всех этих разных плагинов и API. На 2009 год dojox.storage может автоматически определить (и обеспечить универсальный интерфейс) Adobe Flash, Gears, Adobe AIR и ранний прототип хранилища HTML5, который был реализован только в старых версиях Firefox.
В обзоре этих решений есть закономерность: все они либо специфичны для одного браузера, либо полагаются на сторонние плагины. Несмотря на героические усилия, они все радикально различаются интерфейсами, имеют разные ограничения по хранению и предоставляют разные способы взаимодействия с пользователем. Вот проблема, которую в HTML5 необходимо было решить: обеспечить стандартный API, который изначально поддерживается несколькими браузерами без необходимости полагаться на сторонние плагины.
The localStorage Object
The localStorage object stores the data with no expiration date. The data
will not be deleted when the browser is closed, and will be available the next day, week, or year.
Example
// StorelocalStorage.setItem(«lastname», «Smith»);// Retrieve
document.getElementById(«result»).innerHTML = localStorage.getItem(«lastname»);
Example explained:
- Create a localStorage name/value pair with name=»lastname» and value=»Smith»
- Retrieve the value of «lastname» and insert it into the element with id=»result»
The example above could also be written like this:
// StorelocalStorage.lastname = «Smith»;// Retrieve
document.getElementById(«result»).innerHTML = localStorage.lastname;
The syntax for removing the «lastname» localStorage item is as follows:
localStorage.removeItem(«lastname»);
Note: Name/value pairs are always stored as strings.
Remember to convert them to another format when needed!
The following example counts the number of times a user has clicked a button.
In this code the value string is converted to a number to be able to increase the counter:
Example
if (localStorage.clickcount) { localStorage.clickcount = Number(localStorage.clickcount) + 1;
} else { localStorage.clickcount = 1;}
document.getElementById(«result»).innerHTML = «You have clicked the button » +
localStorage.clickcount + » time(s).»;
Приватный просмотр (режим инкогнито)
Большинство современных браузеров поддерживают опцию конфиденциальности «инкогнито», «приватный просмотр», или что-то подобное, что не хранит такие данные, как история и файлы cookie. Это принципиально несовместимо с веб-хранилищем по очевидным причинам, по этой причине поставщики браузеров экспериментируют с различными сценариями устранения этой несовместимости.
Большинство браузеров выбрали стратегию, в которой API хранилища по-прежнему доступны и кажутся полностью функциональными, с той большой разницей, что все сохраненные данные стираются после закрытия браузера. Для этих браузеров все еще существуют различные интерпретации того, что должно быть сделано с существующими сохраненными данными (из обычной сессии просмотра). Затем есть некоторые браузеры, например, Safari, которые выбрали такое решение при котором хранилище доступно, но пусто и имеет квоту 0 байт, что фактически делает невозможным запись в него данных.
Разработчики должны знать об этих различных реализациях и учитывать их при разработке веб-сайтов в зависимости от API веб-хранилища.
Storages
Store.js will pick the best available storage, and automatically falls back to the first available storage that works:
List of all Storages
- all.js All the storages in one handy place.
- localStorage.js Store values in localStorage. Great for all modern browsers.
- sessionStorage.js Store values in sessionStorage.
- cookieStorage.js Store values in cookies. Useful for Safari Private mode.
- memoryStorage.js Store values in memory. Great fallback to ensure store functionality at all times.
- oldFF-globalStorage.js Store values in globalStorage. Only useful for legacy Firefox 3+.
- oldIE-userDataStorage.js Store values in userData. Only useful for legacy IE 6+.
Storages limits
Each storage has different limits, restrictions and overflow behavior on different browser. For example, Android has has a 4.57M localStorage limit in 4.0, a 2.49M limit in 4.1, and a 4.98M limit in 4.2… Yeah.
To simplify things we provide these recommendations to ensure cross browser behavior:
Storage | Targets | Recommendations | More info |
---|---|---|---|
all | All browsers | Store < 1 million characters | (Except Safari Private mode) |
all | All & Private mode | Store < 32 thousand characters | (Including Safari Private mode) |
localStorage | Modern browsers | Max 2mb (~1M chars) | |
sessionStorage | Modern browsers | Max 5mb (~2M chars) | |
cookieStorage | Safari Private mode | Max 4kb (~2K chars) | |
userDataStorage | IE5, IE6 & IE7 | Max 64kb (~32K chars) | |
globalStorage | Firefox 2-5 | Max 5mb (~2M chars) | |
memoryStorage | All browsers, fallback | Does not persist across pages! |
Write your own Storage
Chances are you won’t ever need another storage. But if you do…
See storages/ for examples. Two good examples are memoryStorage and localStorage.
Basically, you just need an object that looks like this:
// Example custom storage var storage = { name: 'myStorage', read: function(key) { ... }, write: function(key, value) { ... }, each: function(fn) { ... }, remove: function(key) { ... }, clearAll: function() { ... } } var store = require('store').createStore(storage)