Labs/Jetpack/JEP/11: Difference between revisions

m
(Updated for asynchronicity)
 
(21 intermediate revisions by 3 users not shown)
Line 3: Line 3:
== JEP 11 - Simple Persistent Storage ==
== JEP 11 - Simple Persistent Storage ==


* Author: Atul Varma <atul at mozilla dot com>
* Author: Drew Willcoxon, <adw at mozilla dot com>
* Champion: Atul Varma <atul at mozilla dot com>
* Editors: Atul Varma <atul at mozilla dot com>, Aza Raskin <aza at mozilla dot com>
* Status: Draft
* Champion: Drew Willcoxon
* Status: Implementing
* Type: API Track
* Type: API Track
* Created: 27 May 2009
* Created: 27 May 2009
* Reference Implementation: None
* Reference Implementation: None
* Relevant Bugs: {{bug|503466}}, {{bug|499871}}, {{bug|496694}}
* [[Labs/Jetpack/JEPs|JEP Index]]
* [[Labs/Jetpack/JEPs|JEP Index]]


=== Introduction and Rationale ===
=== Introduction and Rationale ===


This JEP describes a simple mechanism through which Jetpacks can persistently and asynchronously store JS primitives and blobs of JSON data.  Asynchronicity is desirable because a Jetpack's usage of persistent storage should not block the browser's front-end.
This JEP describes a simple mechanism through which Jetpacks can persistently store JS primitives and blobs of JSON data.
 
The API of this proposal is constrained by what is possible to implement using JavaScript 1.8, since distributing binary components with the Jetpack extension is nontrivial.


This proposal is favored over [https://developer.mozilla.org/Pt/DOM/DOM_Storage DOM Storage] because the latter only supports storing strings, which forces the developer to manually perform error-prone parsing tasks for almost any kind of use case. It should also be noted that the simple storage outlined in this proposal can be implemented on the web using DOM Storage; as such, this proposal should not be considered "breaking the web".
This proposal is favored over [https://developer.mozilla.org/Pt/DOM/DOM_Storage DOM Storage] because the latter only supports storing strings, which forces the developer to manually perform error-prone parsing tasks for almost any kind of use case. It should also be noted that the simple storage outlined in this proposal can be implemented on the web using DOM Storage; as such, this proposal should not be considered "breaking the web".
Line 23: Line 23:
=== Proposal ===
=== Proposal ===


Persistent storage will live at <code>jetpack.storage.simple</code>. The <code>jetpack.storage</code> namespace will provide access to any other available storage systems, such as sqlite, secure/password storage, and so on.  The current <code>jetpack.sessionStorage</code> object, which allows arbitrary JS objects (they need not be JSON-able) to be stored between reloads of a Jetpack within the same Firefox session, will be renamed to <code>jetpack.storage.session</code>.
Simple, persistent storage will live at <code>jetpack.storage.simple</code>. The <code>jetpack.storage</code> namespace will provide access to any other available storage systems, such as SQLite, secure/password storage, and so on.  The current <code>jetpack.sessionStorage</code> object, which allows arbitrary JS objects (they need not be JSON-able) to be stored between reloads of a Jetpack within the same Firefox session, will be renamed to <code>jetpack.storage.session</code>.
 
==== Callbacks ====


Because of the asynchronous nature of this API, its operations communicate their statuses and results to callers via callbacksIn the context of simple storage, a callback is an object that defines the methods <code>onResult</code> and <code>onError</code>.
Simple storage is really simple.  <code>jetpack.storage.simple</code> is a single, persistent JavaScript object available and private to each Jetpack feature.  For the most part this object is like any other JavaScript object, and a feature can set whatever properties it wants on itTo manipulate its persistent data, a feature therefore need only use the various [https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference standard JavaScript functions and operators].


<code>onResult</code> is called when the callback's associated asynchronous operation successfully completes:
The <code>jetpack.simple.storage</code> object is automatically flushed to disk. How and when it is flushed is an implementation detail -- either periodically and on onload or, perhaps in the future if using catch-alls, when a property is set on the object.  Storage may be flushed manually, however, by calling <code>jetpack.storage.simple.sync()</code>.  The object can be forced to reload its data from disk by calling <code>jetpack.storage.simple.open()</code>, although the data comes loaded automatically.


<pre class="brush:js;toolbar:false;">
==== Flushing Storage to Disk ====
callback.onResult(key, [value])
</pre>


<code>onError</code> is called when an error occurs during the operation:
As described above, the <code>jetpack.storage.simple</code> object is automatically written to disk, but a feature may force flush by calling:


<pre class="brush:js;toolbar:false;">
<pre class="brush:js;toolbar:false;">
callback.onError(key, [value,] errorMessage)
jetpack.storage.simple.sync()
</pre>
 
The definitions of <code>key</code> and <code>value</code> vary according to the simple storage operation associated with the callback, and depending on the context <code>value</code> may not be passed at all.  Details follow in the sections below.
 
In the interest of promoting proper coding practices, callbacks are never optional.
 
==== Storing Values ====
 
<pre class="brush:js;toolbar:false;">
jetpack.storage.simple.set(key, value, callback)
</pre>
</pre>


''Arguments''
''Arguments''


<code>key</code>: A string uniquely identifying the data to be placed in persistent storage.  If <code>key</code> is not a string, an exception is thrown.
This method takes no arguments.
 
<code>value</code>: A JS primitive or JSON-able JS object that represents the data to be stored in persistent storage.  If some other data with the given <code>key</code> is already being stored, it is overwritten by <code>value</code>. If <code>value</code> is not a JS primitive or a JSON-able JS object, an exception is thrown.
 
<code>callback</code>: A callback object. The callback's <code>onResult</code> and <code>onError</code> methods will be passed <code>key</code> and <code>value</code>.


''Return value''
''Return value''


This function has no return value.
This method has no return value.


==== Retrieving Values ====
==== Repopulating Storage ====


<pre class="brush:js;toolbar:false;">
As described above, the <code>jetpack.storage.simple</code> object is automatically populated when a feature is loaded, but a feature may force the object to read from disk by calling:
jetpack.storage.simple.get(key, callback)
</pre>
 
''Arguments''
 
<code>key</code>: A string uniquely identifying the data to be retrieved from persistent storage.  If <code>key</code> is not a string, an exception is thrown.
 
<code>callback</code>: A callback object. The callback's <code>onResult</code> method will be passed <code>key</code> and a value.  If <code>key</code> exists in the store, then the value will be <code>key</code>'s associated data.  If no such key exists, then the value will be <code>undefined</code>.  The callback's <code>onError</code> method will be passed only <code>key</code>.
 
''Return value''
 
This function has no return value.
 
==== Removing Values ====


<pre class="brush:js;toolbar:false;">
<pre class="brush:js;toolbar:false;">
jetpack.storage.simple.remove(key, callback)
jetpack.storage.simple.open()
</pre>
</pre>


Removes the key and its associated data from persistent storage. Calling <code>jetpack.storage.simple.remove(key)</code> is the same as calling <code>jetpack.storage.simple.set(key, undefined)</code>.
Note that any properties already on the object will be overwritten, but no properties are deleted before loading.


''Arguments''
''Arguments''


<code>key</code>: The string uniquely identifying the data to be removed from persistent storage.  If <code>key</code> is not a string, an exception is thrown.
This method takes no arguments.
 
<code>callback</code>: A callback object.  The callback's <code>onResult</code> and <code>onError</code> methods will be passed only <code>key</code>.


''Return value''
''Return value''


This function has no return value.
This method has no return value.


==== Other Notes ====
=== Example Usage ===


''Equivalence vs. Equality''
This code persistently stores some data:
 
The values passed into <code>set()</code> and returned from <code>get()</code> are all serialized/de-serialized at the time of calling; this means that, for instance, given the following code:


<pre class="brush:js;toolbar:false;">
<pre class="brush:js;toolbar:false;">
var original = {foo: 'bar'};
jetpack.future.import("storage.simple");
jetpack.storage.simple.set('test', original);
var myStorage = jetpack.storage.simple;
myStorage.fribblefrops = [1, 3, 3, 7];
myStorage.heimelfarbs = { bar: "baz" };
</pre>
</pre>


the following condition will hold:
And then to use these objects later:


<pre class="brush:js;toolbar:false;">
<pre class="brush:js;toolbar:false;">
assert(jetpack.storage.simple.get('test') != original);
var myStorage = jetpack.storage.simple;
myStorage.fribblefrops.forEach(function (elt) console.log(elt));
var bar = myStorage.heimelfarbs.bar;
</pre>
</pre>
That's all there is to it!  (These examples create a <code>myStorage</code> variable to emphasize the fact that <code>jetpack.storage.simple</code> is just a normal JavaScript object.  We could have simply used <code>jetpack.storage.simple</code> directly.)
Confirmed users
764

edits