IndexedDB - the standard for storing large amounts of structured data on the client - was also expected as well as WebSocket (well, maybe just a little less). In the light of the release of FireFox 4, I found time and energy to figure out how to use it, and try to write something more than an example with an address book, walking on the Internet (in the process of searching for information, I got the impression that it was the only example).
A few introductory words
IndexedDB is used to store large amounts of structured data, with the possibility of indexing. The need for such a toolkit was long overdue, which led to its appearance in the HTML5 specifications. A brief background can be found
here .
The text will meet the lyrical digressions required for the release of emotions. I don't want to sprinkle an article with wiki-style links, all sources are folded at the end.
What are we going to train on
It so happened that I recently engaged in the creation of chatik. So we will build a chat, with the following requirements:
- all chat messages are stored locally, no more than 100 recent messages are received from the server;
- also locally stored user settings, in our case - the user name.
Go
The first step is to check if IndexedDB is supported in the browser. This is done like this:
if ("webkitIndexedDB" in window){ var idb=window.webkitIndexedDB; } else if ("mozIndexedDB" in window) { var idb=window.mozIndexedDB; } else {
')
:
, . , , ( ), , , -, .
Next, you need to create an object of type IDBRequest, which will provide asynchronous access to database objects. Synchronous access to IndexedDB in the draft specification is present, but not yet implemented.
var idbRequest=idb.open(dbName,dbDescription);
Onerror hooks:
If you believe the specification, then an object of type IDBErrorEvent, which has two properties, code and message, should fly as an argument. In practice, an event just arrives, fortunately having an IDBRequest object in the properties, from which you can get the error code and, in the case of the webcam, the message itself. The final handler has the following structure:
function idbRequestError(err){ idbRequest=err.target;
To cause this error is quite simple:
- prevent the saving of local data in the browser settings;
- think long over the message FireFox “This site is trying to write data locally. Allow? "
If the connection is successful, you can continue and check whether the user has the necessary database and whether it is the same version. Successful connection handler structure:
function idbRequestSuccess(e){ var db=e.target.result; if (db.version===''){
In the absence of a database or its incorrect version, it would be necessary to create or modify it. To do this, we need the setVersion method. Here, I have to digress from writing code, and talk about the mechanism of transactions in IndexedDB.
Transaction in IndexedDB
The W3C Draft defines four types of transactions: READ_ONLY, READ_WRITE, SNAPSHOT_READ, and VERSION_CHANGED.
, READ_ONLY SNAPSHOT_READ, , , .
READ_ONLY - serves, as the name implies, for reading. Blocks transactions of other types.
READ_WRITE - serves to change data, waits until all competing transactions over the selected object are completed, blocks all other transactions and is executed.
VERSION_CHANGE - a transaction that waits until all other transactions are completed, blocks access to data objects for all and is performed. Only in this transaction can you create, delete or modify data objects.
. W3C READ_WRITE=0, READ_ONLY=1, SNAPSHOT_READ=2, VERSION_CHANGE=3. “webkitIDBTransaction.READ_ONLY” , , . , VERSION_CHANGE 2, . , FireFox READ_ONLY=0, READ_WRITE=1 .
Creating data objects
As already mentioned, you can manipulate data objects only from the VERSION_CHANGE transaction. We can connect to it from the handler for a successful version change.
var setVersion=db.setVersion('3.14'); setVersion.onsuccess=function (e) { var db=e.target.transaction.db;
What can be done with data objects:
Create - createObjectStore ()
Delete - deleteObjectStore ()
Assign transaction - transaction ()
We will deal with the removal
As an argument, the delete method takes the name of the data object to be deleted. The method is executed asynchronously, and in theory, should return an object of type IDBRequest, to which you can attach an onsuccess handler. But neither Webkit nor Mozilla consider it necessary to return anything. The method works, however, asynchronously and blocks access to competing methods. Because the use of designs
for (var i=0; i<db.objectStoreNames.length; i++){ db.deleteObjectStore(db.objectStoreNames.length[i]); };
leads to unpredictable results. Something off, something not. Learn the normal way does not work. The structure of the crutch, in principle, is understandable, but I decided not to bother with this, because To remove objects, you need, by and large, only in the case of a change in the structure of the base.
Creating objects
In the example, with the address book, only one database object was created. But when I decided to create two objects, FireFox began to obscure me on the topic of NON_TRANSIENT_ERR, which roughly means: “not this, and not in that transaction you are doing”.
Initially, the design was as follows, and worked fine in Chrome:
var setVersion=db.setVersion(dbVersion); setVersion.onsuccess=idbCreateStore; function idbCreateStore(e){
After several hours of experiments, a hack was created for FireLisa, which also works in Chrome:
var setVersion=db.setVersion('4'); setVersion.onsuccess=idbCreateStore; function idbCreateStore(e){
As you may have noticed, before the creation of an object, it is checked whether there is already such an object in the database. This is done in order not to bother with the removal of objects. If you try to create an object that is already present in the database, then an error will fall out.
The optional arguments for creating objects are: key name and autoincrement flag (ignored by browsers).
The creation of indexes also disappeared from the code: OgneLis reacted painfully to the creation of indexes in a version change transaction.
At this point, the database is formed. It would seem that you can continue. But it is not. All calls are made asynchronously, therefore it cannot be stated unequivocally that all objects were created. Again, if you believe the specs, the IDBObjectStore object returned by the createObjectStore () method must contain the IDBRequest property, which can be hung with an onsuccess handler. But there is no similar property in the object. Therefore, before starting the main work loop, you must wait until the creation of the database objects is completed, which is done by the following non-tricky code:
var idbObjectsWait=true; while (idbObjectsWait){ idbObjectsWait=!(db.objectStoreNames.contains('chat') && db.objectStoreNames.contains('iam')); };
Finally, the base has been created, and you can start writing to it and reading from it what you have written down.
Record
You can write data in two ways (and only from the record transaction): add and put. The differences are as follows: if a key that is already present in the object is passed to add, the value will not be written; put - replaces the data. The operations are asynchronous again.
var t=idb.transaction(['iam'], idbConst.WRITE); var s=t.objectStore('iam'); s.put({'name':$('#name').val()},1);
Reading
. IDBKeyRange, , . .. : . , : var t=idb.transaction(['chat'],idbConst.READ); var s=t.objectStore('chat'); var r=s.openCursor(); r.onsuccess=function (e) { var idbEntry=e.target.result; if (idbEntry){
You cannot control the initial position of the pointer, but you can steer the reading direction by passing the parameter to the continue method.
Conclusion
Actually, on this not very optimistic note, you can finish. IndexedDB implementation is extremely raw: the cactus is very prickly, and tequila does not come out of it. The range of applications is extremely limited, and writing code for IndexedDB clearly does not pay for itself, including due to the small number of browsers.
What to look for on the topic
mikewest.org/2010/12/intro-to-indexeddb - a very good presentation of Mike West with the very example of an address book, which, although it contains a number of inaccuracies (apparently just the time has passed), is very good to start the proceedings.
developer.mozilla.org/en/IndexedDB is a Mozilla development document.
www.w3.org/TR/IndexedDB - W3C specification.
www.netroxsc.ru/pub/chateg - an example for Chrome, tested in Chrome 11 and 12, and the source code of the project
UPD 2014-04-09 . Updated IndexDB article:
Preparing IndexedDB