<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Jens Arps &#187; Storage</title>
	<atom:link href="http://jensarps.de/tag/storage/feed/" rel="self" type="application/rss+xml" />
	<link>http://jensarps.de</link>
	<description></description>
	<lastBuildDate>Tue, 07 Sep 2010 14:11:57 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>localStorage Performance Test Results</title>
		<link>http://jensarps.de/2010/09/07/localstorage-performance-test-results/</link>
		<comments>http://jensarps.de/2010/09/07/localstorage-performance-test-results/#comments</comments>
		<pubDate>Tue, 07 Sep 2010 11:17:50 +0000</pubDate>
		<dc:creator>Jens Arps</dc:creator>
				<category><![CDATA[Experiments in Web]]></category>
		<category><![CDATA[Storage]]></category>
		<category><![CDATA[client-side storage]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[localStorage]]></category>
		<category><![CDATA[persistence]]></category>

		<guid isPermaLink="false">http://jensarps.de/?p=260</guid>
		<description><![CDATA[It&#8217;s been some time since I last updated this blog, mostly because there&#8217;s plenty going on these days. However, there&#8217;s something I&#8217;ve been wanting to publish for quite some time now: The results of the localStorage performance tests I ran several weeks ago. As I am currently working on performance tests for Mozilla&#8217;s IndexedDB implementation, ]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been some time since I last updated this blog, mostly because there&#8217;s plenty going on these days. However, there&#8217;s something I&#8217;ve been wanting to publish for quite some time now: The results of the localStorage performance tests I ran several weeks ago. As I am currently working on performance tests for Mozilla&#8217;s IndexedDB implementation, which is available in latest Minefield releases, I got reminded that there are still other results to publish – so, here we go:</p>
<p><span id="more-260"></span></p>
<p>Among other tests, the main thing I wanted to know is how long does it take to read or write 1000 entries from/to localStorage. The keys were of the form &#8220;key000&#8243;, the values &#8220;val000&#8243;, with increasing numbers. So the tests were using minimal data – only 6  bytes – but the results are still useful to get an idea of how it goes – and how the browsers perform compared to each other.</p>
<p><strong>Desktop</strong></p>
<p>All test were run on a Mac Mini. Opera and IE were tested on a virtual machine, so there might be an additional performance penalty based on virtualization. However, here are the numbers (average time needed to run the respective method 1000 times):</p>
<p>Safari 4:<br />
- getItem: 1.4ms<br />
- setItem: 1.7ms<br />
- key: 0.8ms</p>
<p>Chrome:<br />
- getItem: 240ms<br />
- setIem: 280ms<br />
- key: 230ms</p>
<p>Firefox:<br />
- getItem: 77ms<br />
- setItem: 2100ms<br />
- key: 25ms</p>
<p>Opera:<br />
- getItem: 19ms<br />
- setItem: 20ms<br />
- key: 18ms</p>
<p>IE8:<br />
- getItem: 5ms<br />
- setItem: 72ms<br />
- key: 3.6ms</p>
<p><strong>Mobile</strong></p>
<p>As we can see, Safari is lightening fast. That made me want to run the tests on a mobile phone that has a modern Safari browser. I took an HTC Desire, wich comes with Android 2.1, and thus has a Safari capable of localStorage. Here are the results:</p>
<p>HTC Desire:<br />
- getItem: 16.4ms<br />
- setItem: 19.5ms<br />
- key: 8.7ms</p>
<p>This is pretty amazing, considering that it is a phone. It still beats most of the browseres on the desktop.</p>
<p>If I find that test page again (uh, yeah, it&#8217;s lost somehow), I&#8217;ll run the tests again with newer browser releases and publish the link here, so you can run the tests yourself.</p>
]]></content:encoded>
			<wfw:commentRss>http://jensarps.de/2010/09/07/localstorage-performance-test-results/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t use Cookies</title>
		<link>http://jensarps.de/2010/04/10/dont-use-cookies-use-localstorage/</link>
		<comments>http://jensarps.de/2010/04/10/dont-use-cookies-use-localstorage/#comments</comments>
		<pubDate>Sat, 10 Apr 2010 17:54:01 +0000</pubDate>
		<dc:creator>Jens Arps</dc:creator>
				<category><![CDATA[Browser Struggle]]></category>
		<category><![CDATA[How to]]></category>
		<category><![CDATA[Storage]]></category>
		<category><![CDATA[client-side storage]]></category>
		<category><![CDATA[cookies]]></category>
		<category><![CDATA[localStorage]]></category>
		<category><![CDATA[persistence]]></category>

		<guid isPermaLink="false">http://jensarps.de/?p=216</guid>
		<description><![CDATA[– or: How to persist data in the 21st century.
The common way to persist data on the client side – application state, offline data, whatever –  still is to use cookies. But times have changed, and so have browsers, and there are better ways to do it today.
But why are cookies that bad? Well, here ]]></description>
			<content:encoded><![CDATA[<p>– or: <strong>How to persist data in the 21st century</strong>.</p>
<p>The common way to persist data on the client side – application state, offline data, whatever –  still is to use cookies. But times have changed, and so have browsers, and there are better ways to do it today.</p>
<p>But why are cookies that bad? Well, here are the top three reasons:</p>
<ol>
<li>Of all client side storage mechanisms, cookies have the worst limitation in size (4k if you want to stay IE-safe)</li>
<li>Cookies are sent to the server on every requests that matches the cookie domain – inlcuding XHR calls (aka. <em>How to slow down your AJAX app</em>)</li>
<li>Cookies perform bad, can be easily disabled, and, oh well, they are sooo 1995…</li>
</ol>
<p>What else to use? There are several options, let&#8217;s start with the best:<br />
<span id="more-216"></span></p>
<h2><strong>localStorage</strong></h2>
<p>This is the storage mechanism proposed by the HTML5 draft. It offers you a fast, reliable key-value store with a whopping 5M (!!) of storage space. And here&#8217;s the kicker: It&#8217;s implemented in all current major browser releases. That is, FF, Safari, Opera, IE and Chrome/Chromium. Yes, you name it, all of them, the full list. To read more about localStorage, check the <a href="http://dev.w3.org/html5/webstorage/" target="_blank">HTML5 draft</a>. But here&#8217;s all you need to know in short:</p>
<p><strong>Storage Methods</strong></p>
<p>To test if the user agent supports localStorage, just test for the existence of <code>window.localStorage</code>. Working with the storage object is trivial:</p>
<p>Setting a value:</p>
<pre>localStorage.setItem('key','value');</pre>
<p>Though the draft says the user agent should write a &#8220;structured clone&#8221; of the value to store, don&#8217;t think that you can store objects – you can only store strings. To store objects, you need to convert them to JSON before.</p>
<p>To retrieve a value, there are two options. First, you can get a value by it&#8217;s key:</p>
<pre>var value = localStorage.getItem('key');</pre>
<p>The user agent will return the value for the key, or, if it doesn&#8217;t find a matching record, <code>null</code>. Also, you can retrieve a key by it&#8217;s index:</p>
<pre>var value = localStorage.key(n);</pre>
<p>The storage object has a <code>length</code> property, and n is a number between zero and length-1. You do not get the index of a value when inserting it, but you can use the <code>key()</code> method when iterating over all items in the store using the <code>length</code> attribute.</p>
<p>There is another method to retrieve a value, but as this not documented (at least I didn&#8217;t find anything about it), I do not recommend it:</p>
<pre>var value = localStorage.key;</pre>
<p>Deleting an item:</p>
<pre>localStorage.removeItem('key');</pre>
<p>Deleting the whole storage:</p>
<pre>localStorage.clear();</pre>
<p>This clears only the storage objects of the same storage area. That is, storage objects of the current domain.</p>
<p>So far, everything is pretty trivial, but let&#8217;s look at</p>
<p><strong>Storage Exceptions</strong></p>
<p>When accessing the storage object, a user agent may raise an <code>SECURITY_ERR</code> exception – but I have never managed to trigger one. When setting an item, a user agent may raise an <code>QUOTA_EXCEEDED_ERR</code> exception. This is not only for the case when storage space is at it&#8217;s limit, but may be raised for other reasons as well. Again, I have never managed to trigger it, but it may be wise to wrap a <code>setItem</code> call in a try/catch block.</p>
<p><strong>Storage Event</strong></p>
<p>Now things get tricky, and the different browsers have different (if any) implementations. Ok, first, the theory: methods that modify the storage object (<code>setItem()</code>,<code>removeItem()</code>,<code>clear()</code>) do not report if – or when – the changes are in effect. To get notified about this, you need to connect to the storage event:</p>
<pre>window.addEventListener("storage", function(evt){
    // a change to the storage object has been attempted.
}, false);</pre>
<p>The event should have the following attributes:</p>
<ul>
<li>key</li>
<li>oldValue</li>
<li>newValue</li>
<li>url (the address of document object whose storage object was modified)</li>
<li>storageArea (the affected storage object)</li>
</ul>
<p>With this information, you can easily determine to what change the storage event belongs. But, alas, that event is not fully implemented everywhere. Here&#8217;s what I found out:</p>
<p><strong>FF 3.6.3 </strong>lets you connect to the event, and fires it according to the draft. But it does not contain *any* of the fields mentioned above.</p>
<p><strong>Safari 4.0.5</strong> lets you connect to the event, and fires it according to the draft. It&#8217;s event contains all attributes except url.</p>
<p>on <strong>Chrome 5 &amp; Chromium</strong> I couldn&#8217;t connect to the event at all or it wouldn&#8217;t let my execute code in my callback function – I have no idea if it&#8217;s even fired.</p>
<p>Latest <strong>WebKit nightly</strong> wouldn&#8217;t report anything to me, like  Chrome.</p>
<p><strong>Opera 10 </strong>lets you connect to the event, fires it accordingly, and the event contains all attributes (woot!)</p>
<p><strong>IE 8</strong> didn&#8217;t report anything back to me, too.</p>
<p>I used <a href="http://www.jensarps.de/tests/storage.html" target="_blank">this simple test file</a> to check for the event. Feel free to test other browsers and report what you found!</p>
<h2><strong>Other options</strong></h2>
<p>If the browser is too old to have localStorage, there are still other options to persist data: Firefox 2 had globalStorage, which behaves similar to localStorage. IE has userData beahvior since version 5.5. Safari has it&#8217;s built-in Sqlite database, but I don&#8217;t know since when. Plus, there&#8217;s also plugin-based storage via Flash or Gears. Only if they all fail, you should get back to cookies.</p>
<p>Of course, it would be a lot of work to write wrappers for all these storage mechanisms – but, hey, you don&#8217;t have to, others have already done it. There are several toolkits that do the work for you, and I will present three of them.</p>
<p><strong>Dojo</strong></p>
<p>The dojo toolkit has dojox.storage. It currently offers support for Flash, Gears and globalStorage. But with the files you can grab at my <a href="http://jensarps.de/2010/01/04/persistent-local-storage-with-dojo/" target="_blank">previous post on storage</a>, you gain access to localStorage, userData behavior and cookies. Working with dojox.storage is pretty simple, and you don&#8217;t have to worry about anything: dojo&#8217;s storage manager will pick the best available provider. Here&#8217;s a simple example:</p>
<pre>dojo.require("dojox.storage");
dojox.storage.put('key','value');
var value = dojox.storage.get('key');</pre>
<p>That&#8217;s it. Simple as that. You do have more options, though; you can also specify a namespace for your keys – so you can simulate working with different &#8220;tables&#8221; in one store. You can also specify a callback function for the <code>put()</code> method, to get notified when the changes are in effect and if the change was successful.</p>
<p><strong>Lawnchair</strong></p>
<p>Lawnchair has been created by <a href="http://twitter.com/brianleroux" target="_blank">Brian Leroux</a> from Nitobi. Working with it is dead simple, too. It supports localStorage, userData behavior, Gears, Webkit&#8217;s Sqlite and Cookies. It works more like a document store (you can save an object w/o specifying a key, for example), but you can also use it like a straight key/value store. In opposition to dojo&#8217;s storage system, Lawnchair works completely asnc, so you have to pass a callback function to a get() method to retrieve a value (being async is not a drawback, and it is neccessary to work with WebKit&#8217;s Sqlite). You can find some docs <a href="http://brianleroux.github.com/lawnchair/" target="_blank">here</a> and get it over <a href="http://github.com/brianleroux/lawnchair" target="_blank">at Github</a>.</p>
<p><strong>Persist.js</strong></p>
<p>Persist.js has support for localStorage, globalStorage, Gears, Flash, userData behavior and Cookies. It also works completely async. You can get it <a href="http://github.com/lloyd/persist-js" target="_blank">at Github</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://jensarps.de/2010/04/10/dont-use-cookies-use-localstorage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>persistent local storage with dojo</title>
		<link>http://jensarps.de/2010/01/04/persistent-local-storage-with-dojo/</link>
		<comments>http://jensarps.de/2010/01/04/persistent-local-storage-with-dojo/#comments</comments>
		<pubDate>Mon, 04 Jan 2010 21:46:40 +0000</pubDate>
		<dc:creator>Jens Arps</dc:creator>
				<category><![CDATA[Dojo Love]]></category>
		<category><![CDATA[Experiments in Web]]></category>
		<category><![CDATA[Goodies to go]]></category>
		<category><![CDATA[Storage]]></category>
		<category><![CDATA[client-side storage]]></category>
		<category><![CDATA[dojo]]></category>
		<category><![CDATA[dojox]]></category>
		<category><![CDATA[js]]></category>
		<category><![CDATA[local]]></category>
		<category><![CDATA[localStorage]]></category>
		<category><![CDATA[persistence]]></category>

		<guid isPermaLink="false">http://jensarps.de/?p=140</guid>
		<description><![CDATA[Last year, Brian Leroux&#8217;s Lawnchair caught my interest – it is an easy and fast way to access local persistant local storage.
Uh, persistant local storage?
Ahm, yeah, in case you don&#8217;t know, that means a client-side storage, be it in a browser, or in an Air app. It&#8217;s not very popular, but that concept has been ]]></description>
			<content:encoded><![CDATA[<p>Last year, <a href="http://twitter.com/brianleroux" target="_blank">Brian Leroux</a>&#8217;s <a href="http://brianleroux.github.com/lawnchair/" target="_blank">Lawnchair</a> caught my interest – it is an easy and fast way to access local persistant local storage.</p>
<p><strong>Uh, persistant local storage?</strong></p>
<p>Ahm, yeah, in case you don&#8217;t know, that means a client-side storage, be it in a browser, or in an Air app. It&#8217;s not very popular, but that concept has been around for a long time. So why local? There are two major reasons for it: First, we need this for apps and tools that work offline – and apps and tools that work online but need an offline backup and sync later. <a href="http://twitter.com/kriszyp" target="_blank">Kris Zyp</a> wrote a <a href="http://www.sitepen.com/blog/2008/09/23/effortless-offline-with-offlinerest/" target="_blank">post about the JsonRestStore and OfflineRest</a> back in 2008, he goes a little into detail there. Secondly, we need it for apps and tools that rely on persistence for other reasons, no matter if online or offline – like it happended to me. When I ran into Lawnchair, I had the idea to build a tool that was monitoring CSS selector usage on websites and apps (you know how you sometimes lose control about CSS selectors in webapps…). To achieve this, I needed to store data locally, and persistent.<br />
<span id="more-140"></span><br />
<strong>What dojo offers<br />
</strong></p>
<p>As I was using dojo&#8217;s excellent CSSRuleStore to find out what selectors where used, I wanted to switch from Lawnchair to a dojo solution. Dojo has dojox.storage (the above mentioned OfflineRest uses dojox.storage), which provides wrappers for the following backends: Gears, Flash, globalStorage and Adobe Air (globalStorage is Firefox&#8217;s early implementation of the early WhatWG storage draft). Hm. Not that much. Gears and Flash are 3rd party solutions, globalStorage is a Firefox-only-thingy (and old, though it&#8217;s still supported in current Versions) and Air is non-browser. That means: No IE without plugins. No Safari when Flash is not available.</p>
<p><strong>What dojo does not offer (but should)</strong></p>
<p>Guaranteed, reliable support for *any* browser. Without depending on 3rd party plugins. As of now, to have this, you&#8217;d need to use Lawnchair or <a href="http://github.com/lloyd/persist-js" target="_blank">persist,js</a>, which is pretty complete. Speaking of it, let me quote from it&#8217;s readme (it&#8217;s a good read on local persistent storage in general):</p>
<blockquote><p>The most notable attempt at addressing this problem [storing client-side persistent data] is probably Dojo Storage.  Unfortunately, Dojo Storage does not support Internet Explorer without Flash, and it does not support Safari or other WebKit-based<br />
browsers at all (at least, not without Flash).  Also, Dojo Storage is<br />
not standalone; it requires a several other Dojo components in order to<br />
operate.</p></blockquote>
<p>Whoa, even other JS tools mention the lack of support in dojo…</p>
<p><strong>New providers</strong></p>
<p>Attached to this post are wrappers for the following mechanisms:</p>
<ul>
<li>localStorage: this is the current spec, and it is supported by IE8, Firefox 3, Safari 4, Opera 10, Chrome 5.</li>
<li>userData behavior: this is Microsofts client-side storage for IE &lt; 8.</li>
<li>cookie: worst case fallback solution…</li>
</ul>
<p>With these three, there&#8217;s an almost 100% coverage of browser situations (see storage overview). There are still no-go scenarios, of course, such as IE7 with userData disabled and cookies disabled, but there&#8217;s no way to address them all.</p>
<p><strong>Notes on BehaviorStorageProvider</strong></p>
<p>This one uses the <a href="http://msdn.microsoft.com/en-us/library/ms531424%28VS.85%29.aspx" target="_blank">userData behavior</a>, present in IE from version 5 up. It works with DOM elements that have a special behavior assigned. You can then use  set/get/removeAttribute() methods to store data. It has some limitations though – of course…</p>
<ul>
<li>Maximum size varies from 64k to 1M – depending on the zone the site is in. So, you can&#8217;t rely on more than 64k.</li>
<li>UserData can be switched off in security settings.</li>
<li>I couldn&#8217;t find a way to read out stored keys if you don&#8217;t know them. Maybe this is some security thingy or just a bug – but it means that some methods in the provider don&#8217;t work. (that is, getNamespaces, getKeys and clear). To work around this, we have to take some of the precious storage space and store the keys and namespaces seperately.</li>
</ul>
<p><strong>Usage</strong></p>
<p>Copy the the providers into your <code>/dojox/storage</code> directory and add the needed <code>dojo.require</code>s to <code>/dojox/storage/_common.js</code>:</p>
<pre>dojo.require("dojox.storage.LocalStorageProvider");
dojo.require("dojox.storage.GearsStorageProvider");
dojo.require("dojox.storage.BehaviorStorageProvider");
//&gt;&gt;excludeStart("offlineProfileExclude", kwArgs.dojoxStorageBuildOption == "offline");
dojo.require("dojox.storage.WhatWGStorageProvider");
dojo.require("dojox.storage.FlashStorageProvider");
//&gt;&gt;excludeEnd("offlineProfileExclude");
dojo.require("dojox.storage.CookieStorageProvider");</pre>
<p><strong>What&#8217;s left?</strong></p>
<p>Well, it would be pretty cool to have a dojo.data API compliant store that uses dojox.storage as backend, so that you could write your apps using dojo.data calls and have a reliable offline backup. I started working on that, but then came Christmas, parents, vacation, new year and a lot of beer. But hey, it&#8217;s 2010 now, and there&#8217;s plenty of time left!</p>
<p><strong>Storage Overview</strong><br />
<!-- .overviewTable td {font-size: 10px; padding:2px 5px;} --></p>
<table class="overviewTable" border="0">
<tbody>
<tr>
<td>IE 6 / IE7</td>
<td>BehaviorStorageProvider<br />
FlashStorageProvider<br />
GearsStorageProvider<br />
CookieStorageProvider</td>
</tr>
<tr>
<td>IE 8</td>
<td>LocalStorageProvider<br />
GearsStorageProvider<br />
FlashStorageProvider<br />
CookieStorageProvider</td>
</tr>
<tr>
<td>Safari 3</td>
<td>FlashStorageProvider<br />
CookieStorageProvider</td>
</tr>
<tr>
<td>Safari 4</td>
<td>LocalStorageProvider<br />
FlashStorageProvider<br />
CookieStorageProvider</td>
</tr>
<tr>
<td>Chrome 5</td>
<td>LocalStorageProvider<br />
FlashStorageProvider<br />
CookieStorageProvider</td>
</tr>
<tr>
<td>Firefox 2</td>
<td>WhatWGStorageProvider (= globalStorage)<br />
GearsStorageProvider<br />
FlashStorageProvider<br />
CookieStorageProvider</td>
</tr>
<tr>
<td>Firefox 3</td>
<td>LocalStorageProvider<br />
GearsStorageProvider<br />
FlashStorageProvider<br />
CookieStorageProvider</td>
</tr>
<tr>
<td>Opera 10</td>
<td>LocalStorageProvider<br />
FlashStorageProvider (?)<br />
CookieStorageProvider</td>
</tr>
</tbody>
</table>
<p><strong>Files</strong></p>
<p><a href="http://jensarps.de/tests/dojo_tests/dojo-release-1.4.0-src/dojox/storage/LocalStorageProvider.js" target="_blank">LocalStorageProvider.js</a><br />
<a href="http://jensarps.de/tests/dojo_tests/dojo-release-1.4.0-src/dojox/storage/BehaviorStorageProvider.js" target="_blank">BehaviorStorageProvider.js</a><br />
<a href="http://jensarps.de/tests/dojo_tests/dojo-release-1.4.0-src/dojox/storage/CookieStorageProvider.js" target="_blank">CookieStorageProvider.js</a><br />
<a href="http://jensarps.de/tests/dojo_tests/dojo-release-1.4.0-src/dojox/storage/tests/test_storage.html" target="_blank">Storage Test Page</a></p>
]]></content:encoded>
			<wfw:commentRss>http://jensarps.de/2010/01/04/persistent-local-storage-with-dojo/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
