1. Overview
With the increasing functionality of browsers, more and more websites are considering storing large amounts of data on the client side so that they can get less data from the server and get it directly from the local area.
The existing browser data storage solutions are not suitable for storing large amounts of data: Cookie size is no more than 4KB and each request is sent back to the server; LocalStorage is between 2.5MB and 10MB (varies from browser to browser), and does not provide search function and cannot build custom index. So, a new solution was needed, and this is the background of the birth of IndexedDB.
In layman’s terms, IndexedDB is a browser-provided local database that can be created and manipulated by web scripts; IndexedDB allows storage of large amounts of data, provides a lookup interface, and can build indexes. This is something that LocalStorage does not have. In terms of database type, IndexedDB is not a relational database (does not support SQL query statements), but is closer to a NoSQL database.
IndexedDB has the following features.
- Key-value pair storage. IndexedDB uses an object store to store data internally. All types of data can be stored directly, including JavaScript objects. In the object store, data is stored as “key-value pairs”, and each data record has a corresponding primary key, which is unique and cannot be duplicated, otherwise an error will be thrown.
- Asynchronous. IndexedDB operations do not lock the browser and the user can still perform other operations, in contrast to LocalStorage, where operations are synchronous. The asynchronous design is designed to prevent large amounts of data from being read and written, slowing down the performance of the page.
- Support transaction. IndexedDB supports transaction, which means that if one step in a series of operation steps fails, the whole transaction is cancelled and the database is rolled back to the state before the transaction occurred, without rewriting only a part of the data.
- Homologation Restriction IndexedDB is subject to homologation restriction, each database corresponds to the domain name where it was created. Web pages can only access databases under their own domain name, not cross-domain databases.
- Large storage space The storage space of IndexedDB is much larger than LocalStorage, generally not less than 250MB, and even no upper limit.
- Supports binary storage. IndexedDB can store not only strings, but also binary data (ArrayBuffer objects and Blob objects).
2. Basic Concept
IndexedDB is a complex API that involves a number of concepts. It takes different entities and abstracts them into one object interface. To learn this API is to learn its various object interfaces.
- Database: IDBDatabase object
- Object repository: IDBObjectStore object
- Index: IDBIndex object
- Transaction: IDBTransaction object
- Operation request: IDBRequest object
- Pointer: IDBCursor object
- Primary key collection: IDBKeyRange object
Here are some of the main concepts.
-
Database
IndexedDB databases have the concept of versioning. Only one version of the database can exist at the same moment. If you want to modify the database structure (add or delete tables, indexes or primary keys), you can only do it by upgrading the database version.
-
Object Warehouse
Each database contains a number of object stores. It is similar to a table in a relational database.
-
Data Recording
The object repository holds data records. Each record is similar to a row in a relational database, but has only two parts, the primary key and the data body. The primary key is used to create the default index and must be different or an error will be reported. The primary key can be an attribute inside the data record, or it can be specified as an incremental integer number.
1
{ id: 1, text: 'foo' }
In the above object, the id attribute can be used as the primary key.
The data body can be of any data type, not limited to objects.
-
Index
To speed up data retrieval, indexes can be created for different attributes inside the object repository.
-
Transaction The reading, writing, and deleting of thransaction data records are done through transactions. The transaction object provides three events
error
,abort
andcomplete
to listen to the result of the operation.
3. Operation process
The various operations of the IndexedDB database are generally performed according to the following flow. This section only gives simple code examples for quick start, see here for detailed API of each object.
3.1. Open database
The first step to use IndexedDB is to open the database, using the indexedDB.open()
method.
|
|
This method accepts two parameters. The first parameter is a string indicating the name of the database. If the specified database does not exist, a new database will be created. The second parameter is an integer, which indicates the version of the database. If omitted, it defaults to the current version when opening an existing database, and to 1 when creating a new database.
The indexedDB.open()
method returns an IDBRequest
object. This object handles the result of the open database operation through three events error
, success
, and upgradeneeded
.
1. error event
The error event indicates a failure to open the database.
2. success event
The success event indicates that the database was successfully opened.
At this point, the database object is obtained through the result
property of the request
object.
3. upgradeneeded
event
If the specified version number, is greater than the actual version number of the database, the database upgrade event upgradeneeded will occur.
At this point, the database instance is obtained through the target.result
property of the event object.
3.2. Create a new database
Creating a new database is the same operation as opening a database. If the specified database does not exist, it will be created. The difference is that the subsequent operation is mainly done inside the listener function of the upgradeneeded
event, which is triggered because this is when the version goes from nothing to something.
Usually, the first thing you do after creating a new database is to create a new object repository (i.e., a new table).
In the above code, after the database is created successfully, a new table called person
is added, and the primary key is id.
A better way to write it is to determine if the table exists, and then create it if it does not.
The primary key (key) is the attribute that builds the index by default. For example, if the data record is { id: 1, name: ‘Zhang San’ }, then the id property can be used as the primary key. The primary key can also be specified as an attribute of the next level object, for example { foo: { bar: 'baz' } }
of foo.ba
r can also be specified as the primary key.
If there is no property inside the data record that is suitable as a primary key, then you can let IndexedDB generate the primary key automatically.
In the above code, the primary key is specified as an incremental integer.
After creating a new object repository, you can create a new index in the next step.
In the above code, the three parameters of IDBObject.createIndex()
are the name of the index, the property where the index is located, and the configuration object (indicating whether the property contains duplicate values).
3.3. New Data
Adding data refers to writing data records to the object repository. This needs to be done through a transaction.
|
|
In the above code, a new transaction is required to write the data. When creating a new transaction, you must specify the name of the form and the operation mode (“read-only” or “read-write”). After the new transaction is created, the IDBTransaction.objectStore(name)
method is used to get the IDBObjectStore
object, and then the add()
method of the form object is used to write a record to the form.
The write operation is an asynchronous operation that listens to the success
event and the error
event of the connection object to know whether the write was successful.
3.4. Read data
Reading data is also done through transactions.
|
|
In the above code, the objectStore.get()
method is used to read the data, and the parameter is the value of the primary key.
3.5. Traversing data
To iterate through all records of a data table, use the pointer object IDBCursor
|
|
In the above code, the openCursor()
method of the new pointer object is an asynchronous operation, so it should listen to the success
event.
3.6. Update data
To update the data use the IDBObject.put()
method.
|
|
In the above code, the put()
method automatically updates the record whose primary key is 1
.
3.7. Delete Data
The IDBObjectStore.delete()
method is used to delete records.
3.8. Using the Index
The point of an index is that it allows you to search any field, i.e. get the data record from any field. If you don’t create an index, by default you can only search for the primary key (i.e. take the value from the primary key).
Assume that when you create a new table, an index is created for the name field.
|
|
Now, it is possible to find the corresponding data record from name.
|
|
Reference https://www.ruanyifeng.com/blog/2018/07/indexeddb.html