1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * Adapted from https://github.com/mozilla-b2g/gaia/blob/f09993563fb5fec4393eb71816ce76cb00463190/shared/js/async_storage.js
8 * (converted to use Promises instead of callbacks).
10 * This file defines an asynchronous version of the localStorage API, backed by
11 * an IndexedDB database. It creates a global asyncStorage object that has
12 * methods like the localStorage object.
14 * To store a value use setItem:
16 * asyncStorage.setItem("key", "value");
18 * This returns a promise in case you want confirmation that the value has been stored.
20 * asyncStorage.setItem("key", "newvalue").then(function() {
21 * console.log("new value stored");
24 * To read a value, call getItem(), but note that you must wait for a promise
25 * resolution for the value to be retrieved.
27 * asyncStorage.getItem("key").then(function(value) {
28 * console.log("The value of key is:", value);
31 * Note that unlike localStorage, asyncStorage does not allow you to store and
32 * retrieve values by setting and querying properties directly. You cannot just
33 * write asyncStorage.key; you have to explicitly call setItem() or getItem().
35 * removeItem(), clear(), length(), and key() are like the same-named methods of
36 * localStorage, and all return a promise.
38 * The asynchronous nature of getItem() makes it tricky to retrieve multiple
39 * values. But unlike localStorage, asyncStorage does not require the values you
40 * store to be strings. So if you need to save multiple values and want to
41 * retrieve them together, in a single asynchronous operation, just group the
42 * values into a single object. The properties of this object may not include
43 * DOM elements, but they may include things like Blobs and typed arrays.
49 const DBNAME
= "devtools-async-storage";
51 const STORENAME
= "keyvaluepairs";
54 loader
.lazyRequireGetter(
57 "resource://devtools/shared/indexed-db.js"
60 function withStore(type
, onsuccess
, onerror
) {
62 const transaction
= db
.transaction(STORENAME
, type
);
63 const store
= transaction
.objectStore(STORENAME
);
66 const openreq
= indexedDB
.open(DBNAME
, DBVERSION
);
67 openreq
.onerror
= function withStoreOnError() {
70 openreq
.onupgradeneeded
= function withStoreOnUpgradeNeeded() {
71 // First time setup: create an empty object store
72 openreq
.result
.createObjectStore(STORENAME
);
74 openreq
.onsuccess
= function withStoreOnSuccess() {
76 const transaction
= db
.transaction(STORENAME
, type
);
77 const store
= transaction
.objectStore(STORENAME
);
83 function getItem(itemKey
) {
84 return new Promise((resolve
, reject
) => {
89 store
.transaction
.oncomplete
= function onComplete() {
90 let value
= req
.result
;
91 if (value
=== undefined) {
96 req
= store
.get(itemKey
);
97 req
.onerror
= function getItemOnError() {
98 console
.error("Error in asyncStorage.getItem():", req
.error
.name
);
107 function setItem(itemKey
, value
) {
108 return new Promise((resolve
, reject
) => {
112 store
.transaction
.oncomplete
= resolve
;
113 const req
= store
.put(value
, itemKey
);
114 req
.onerror
= function setItemOnError() {
115 console
.error("Error in asyncStorage.setItem():", req
.error
.name
);
124 function removeItem(itemKey
) {
125 return new Promise((resolve
, reject
) => {
129 store
.transaction
.oncomplete
= resolve
;
130 const req
= store
.delete(itemKey
);
131 req
.onerror
= function removeItemOnError() {
132 console
.error("Error in asyncStorage.removeItem():", req
.error
.name
);
142 return new Promise((resolve
, reject
) => {
146 store
.transaction
.oncomplete
= resolve
;
147 const req
= store
.clear();
148 req
.onerror
= function clearOnError() {
149 console
.error("Error in asyncStorage.clear():", req
.error
.name
);
159 return new Promise((resolve
, reject
) => {
164 store
.transaction
.oncomplete
= function onComplete() {
168 req
.onerror
= function lengthOnError() {
169 console
.error("Error in asyncStorage.length():", req
.error
.name
);
170 reject(req
.error
.name
);
179 return new Promise((resolve
, reject
) => {
189 store
.transaction
.oncomplete
= function onComplete() {
190 const cursor
= req
.result
;
191 resolve(cursor
? cursor
.key
: null);
193 let advanced
= false;
194 req
= store
.openCursor();
195 req
.onsuccess
= function keyOnSuccess() {
196 const cursor
= req
.result
;
198 // this means there weren"t enough keys
201 if (n
=== 0 || advanced
) {
202 // Either 1) we have the first key, return it if that's what they
203 // wanted, or 2) we"ve got the nth key.
207 // Otherwise, ask the cursor to skip ahead n records
211 req
.onerror
= function keyOnError() {
212 console
.error("Error in asyncStorage.key():", req
.error
.name
);
221 exports
.getItem
= getItem
;
222 exports
.setItem
= setItem
;
223 exports
.removeItem
= removeItem
;
224 exports
.clear
= clear
;
225 exports
.length
= length
;