In our daily work, zhihu and I often see a question:

Is the front end still hot?

I just want to say this:

People watching the fire from a distance can never understand the cause of the fire. Only when you are in a storm can you find the eye of the wind — the “Bright Moon of qin Dynasty”.

How can you judge the current development of the front end if you don’t look at it? Should I try something else? Why am I so keen on new technology? The main reason lies in the fear of being eliminated by a subversive content, falling behind from the frontier field. Say a word is: poor, so can only learn… . So this article will take a look at the development of IndexedDB in the front end.

IndexedDB is now slowly gaining popularity and adoption on the front end. It is moving in the direction of front-end offline database technology. IndexedDB, which started with Manifest, localStorage, cookies, and then webSQL, is now being accepted by major browsers. We can also develop innovative technologies for it. For example, with the popularity of small videos, we could cache them in cacheStorage and use WebRTC to control P2P distribution while the user is watching, but be careful to use size wisely, otherwise the consequences could be serious.

The overall architecture of indexedDB is composed of a series of separate concepts, all of which are listed below. There is no logic at first glance, but here I have drawn a logical diagram, which is strung together by function calls.

  • IDBRequest
  • IDBFactory
  • IDBDatabase
  • IDBObjectStore
  • IDBIndex
  • IDBKeyRange
  • IDBCursor
  • IDBTransaction

The overall logic diagram is as follows:

TL; DR

The following introduces the basic concepts of indexedDB and the practical code in practice.

  • Basic concepts of indexedDB. IndexedDB divides the overall data structure according to the index index.
  • Updating the indexedDB database is a pain in the neck because, with the flexibility of the Web, you need to update both the upward version and the downward version to improve fault tolerance.
  • IndexedDB efficient indexing mechanism, internally, indexedDB already providesindex,cursorSuch efficient indexing mechanism, do not directly take all the data back, and then filter, but directly usecursorCarry on.
  • Finally, several common libraries are recommended

More can follow my official account: Front-end Little Jimmy (QR code at the bottom of the article)

Offline storage

IndexedDB can store a large amount of data, such as objects,files,blobs, etc. The storage structure in IndexedDB is based on the Database. Each DB can have different object stores. The specific structure is shown as follows:

In addition, we can set the key to a specific value, and then when we index, we can get the specific content directly from the key. When using IndexDB, it is important to note that it follows the homodomain principle.

Basic concepts of indexDB

In indexDB, there are several basic operation objects:

  • The Database:openMethod directly open, you can get an instance DB. You can create more than one DB per page, but it’s usually one.
idb.open(name, version, upgradeCallback)
Copy the code
  • Object Store: This is the Object stored in DB. This can correspond to the contents of a table in SQL. Its storage structure is as follows:

  • Index: Similar to external chain, it is a kind of Object store. It is mainly used to index data in other Object Store in ontology store. The difference is that key and index are different. For details, see index DEMO, MDN index. As shown below:

The following code is:

Var myIndex = objectStore.index('lName'); 
Copy the code
  • Transaction: A transaction is simply a collection of cruDS. If one of the links fails, the entire transaction is cancelled. Such as:
var trans1 = db.transaction("foo"."readwrite");
var trans2 = db.transaction("foo"."readwrite");
var objectStore2 = trans2.objectStore("foo")
var objectStore1 = trans1.objectStore("foo")
objectStore2.put("2"."key");
objectStore1.put("1"."key");
Copy the code
  • Cursor: Is used to walk over the data contents in DB. Mainly throughopenCursorTo control.
function displayData() {
  var transaction = db.transaction(['rushAlbumList']."readonly");
  var objectStore = transaction.objectStore('rushAlbumList');

  objectStore.openCursor().onsuccess = function(event) {
    var cursor = event.target.result;
    if(cursor) {
      var listItem = document.createElement('li');
      listItem.innerHTML = cursor.value.albumTitle + ', ' + cursor.value.year;
      list.appendChild(listItem);  

      cursor.continue();
    } else {
      console.log('Entries all displayed.'); }}; }Copy the code

How do I use IndexDB

There are some basic concepts. So let’s try IndexDB. Getting started with IndexDB is really about doing a few basic things

  • Open a database table
  • Sets the specified primary Key
  • Define the index of the index

To build an IndexedDB, the following is a simple code:

var request = indexedDB.open(dbName, 2);

request.onerror = function(event) {// The error handler is here. }; request.onupgradeneeded =function(event) { var db = event.target.result; // Set the ID to primaryKey var objectStore = db.createObjectStore("customers", { keyPath: "id",{autoIncrement:true}}); // Set the specified index and ensure that the unique objectStore.createIndex("name"."name", { unique: false });
  objectStore.createIndex("email"."email", { unique: true });

};
Copy the code

There are three main things done above:

  • Open a database table
  • Create a Store and set the primary Key
  • Set up the index

Opening a database table is all about the version number and name, so we don’t have to talk too much about it. Let’s start by creating a store.

Create Object Store

The method used is the createObjectStore method on IDBDatabase.

var objectStore = db.createObjectStore("customers", { keyPath: "id",{autoIncrement:true}});Copy the code

The basic function is constructed as:

IDBObjectStore createObjectStore(DOMString name,
                                               optional IDBObjectStoreParameters options)
                                               
dictionary IDBObjectStoreParameters {
  (DOMString or sequence<DOMString>)? keyPath = null;
  boolean autoIncrement = false;
};
Copy the code
  • KeyPath: Key used to set the primary key. See keyPath and generator below for details.
  • AutoIncrement: Indicates whether to use the autoIncrement key feature.

The key is created primarily to ensure a unique identity for data insertion.

In practice, aiD-keys are also needed to complete the secondary index work, which is mapped to index in IndexDB.

Setting index index

After PK(Primary key) is created, we need to create index for better search performance. This can be used directly:

objectStore.createIndex('indexName'.'property', options);
Copy the code
  • IndexName: Sets the name of the current index
  • Property: Indicates the property referred to by index from the stored data.

Where, options has three options:

  • Unique: Whether the current key can be repeated (most commonly used)
  • MultiEntry: When setting the current property to an array, each element in the array is assigned an index value.
TitleIndex: titleIndex: titleIndex: titleIndex
DB.createIndex('titleIndex'.'title', {unique: false});
Copy the code

For details, see MDN createIndex Prop and googleDeveloper Index.

Add or delete data

Adding and deleting data in IndexedDB is done in a transaction. The add and delete data can be understood as a request, which is equivalent to a request that manages all the current logical operations in a transaction. So, before we start the data manipulation, we need to give you a brief introduction to how to create a transaction.

Transaction creation

Transaction API, as shown below [Code 1]. At creation time, you need to manually specify what type of operation the current transaction is. Basic things include:

  • “Readonly” : read only
  • “Readwrite” : reading and writing
  • “Versionchange” : this cannot be specified manuallyupgradeneededAutomatically created in callback events. It can be used to modify existing object Store structure data, such as index, etc.

You can create this by using the TRANSACTION method on IDBDataBase after the database is opened, as shown in [Code 2].

[NewObject] IDBTransaction Transaction ((DOMString or sequence<DOMString>) storeNames, optional IDBTransactionMode mode ="readonly"); Var transaction = db.transaction(["customers"]."readwrite");
var objectStore = transaction.objectStore("customers");
Walk through the stored data
for (var i in customerData) {
  var request = objectStore.add(customerData[i]);
  request.onsuccess = function(event) {
    // success, done?
  };
}
Copy the code

When a transaction is created, you can specify not only the mode of execution, but also the ObjectStore scope that can be affected by the transaction. Then open multiple oss to operate with objectStore() method as follows [Code 3].

Var tx = db.transaction(["books"."person"]."readonly");
var books = tx.objectStore("books");
var person = tx.objectStore("person");
Copy the code

Operational data

After the transaction is created, we can begin to interact with the data in earnest, that is, to write our specific business logic. As follows [Code 1], a complete data transaction operation.

Var tx = db.transaction("books"."readwrite");
var store = tx.objectStore("books");

store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});

tx.oncomplete = function() {
  // All requests have succeeded and the transaction has committed.
};
Copy the code

With the IDBObjectStore object obtained by the objectStore callback, we can add, delete and change some columns. See [Code 2]. For details, please refer to appendix at the end of this paper.

[Code 2] [NewObject] IDBRequest put(any value, optional any key); [NewObject] IDBRequest add(any value, optional any key); [NewObject] IDBRequest delete(any query);Copy the code

The index data

Index data is the most important of all databases. Here, we can do it using the cursor index. For example, to quickly index key values by index, see [Code 1].

Var index = objectStore.index("name");
index.get("Donna").onsuccess = function(event) {
  alert("Donna's SSN is " + event.target.result.ssn);
};
Copy the code

For more details, see the following data index method.

KeyPath and key Generator

KeyPath and keyGenerator are some of the trickier concepts in IndexedDB. In simple terms, when creating an IndexedDB Store, the data in the Store must be unique, and a primary Key must be set to distinguish between different data, as is the case with other databases. KeyPath and Generator are two different ways of setting keys.

Set the keyPath

Set the data to be stored in advance

const customerData = [
  { ssn: "444-44-4444", name: "Bill", age: 35, email: "[email protected]" },
  { ssn: "555-55-5555", name: "Donna", age: 32, email: "[email protected]"}];Set the Primary Key to keyPath
var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });
Copy the code

Because the SSN is unique in this data set, we can use it as a keyPath to ensure unique characteristics. Or, you can set it to an incremented key, like id++ or something like that.

upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement:true});
Copy the code

The use of the generator

The Generator automatically creates a unique value each time data is added. This unique value is separate from your actual data. AutoIncrement: True

upgradeDb.createObjectStore('notes', {autoIncrement:true});
Copy the code

Precautions for opening indexDB

Check whether indexDB is supported

if(! ('indexedDB' in window)) {
  console.log('This browser doesn\'t support IndexedDB'); return; }Copy the code

Version updated: indexDB

When generating an indexDB instance, you need to manually specify a version number. And the most commonly used

idb.open('test-db7', 2, function(upgradeDb) {})
Copy the code

This can cause A problem, for example, during the online process, user A’s first request is returned to the new version of the page, connected to version 2. After that, I refreshed the web page and hit another offline machine, connecting to the old version 1 error. The main reasons are:

The indexedDB API does not allow the data warehouse in the database to change within the same release. In addition, the current DB version cannot be connected to the version of the earlier version.

For example, you might start by defining the DB version as:

# Content defined in Version 1
db.version(1).stores({friends: "++id,name"});

Version 2 changes the structure to:
db.version(2).stores({friends: "++id,name,shoeSize"});
Copy the code

If the user opens version(1) and then gets version(2) of HTML, an error error will occur.

Reference:

Version of the replacement

Version update

This is an important question in IndexDB. The main reason is that

The indexedDB API does not allow the data warehouse in the database to change within the same release. In addition, the current DB version cannot be connected to the version of the earlier version.

The above can be abstracted as a question:

When do you need to update the version of IndexDB?

  1. This table is in the databasekeyPathAt the right time.
  2. When you need to redesign the database table structure, such as adding index
# version 1 DB design with a primary key ID and index-name
db
.version(1)
.stores({friends: '++id,name'})

# If you want to create a new key, such as male, you will not succeed
db
.version(1)
.stores({friends: '++id,name,male'})

The correct way is to directly modify the version number update
db
.version(2)
.stores({friends: '++id,name,male'})
Copy the code

However, if you change the version number directly, you get a case like this:

  • Due to the original HTML update problem, the user first went to version 1 PAGE A, and then to the updated page B. At this point, the IndexDB is successfully updated to the higher version. However, the next time A user hits an older version of PAGE A, which is still connected to the lower version of IndexDB, an error will be reported, causing you to fail to access.

The solution is to set up the filter and manually pass in the version number when open:

Open the version 1 database
var dbPromise = idb.open('db1', 1, function(upgradeDb){... })Open the version 2 database
var dbPromise = idb.open('db2', 2, function(upgradeDb){... })Copy the code

However, this creates another problem, namely, data migration (older versions of data, it is impossible to get rid of). IndexDB will have an updateCallback that you can use to perform data migration directly.

var dbPromise = idb.open('test-db7', 2, function(upgradeDb) {
  switch (upgradeDb.oldVersion) {
    case 0:
      upgradeDb.createObjectStore('store', {keyPath: 'name'});
    case 1:
      var peopleStore = upgradeDb.transaction.objectStore('store');
      peopleStore.createIndex('price'.'price'); }});Copy the code

In this case, if your version is already 3, you will need to deal with version 2 data:

# split name from version 2 into firstName and lastName
db.version(3).stores({friends: "++id,shoeSize,firstName,lastName"}).upgrade(function(t) {
    
    return t.friends.toCollection().modify(function(friend) {
        // Modify each friend:
        friend.firstName = friend.name.split(' ') [0]; friend.lastName = friend.name.split(' ') [1]; delete friend.name; }); });Copy the code

This is OK for users who have a version 2 database, but for some users who have not yet accessed your database, this is definitely an error. Solutions include:

  • Preserve the fields and stores created with each version
  • In the update callback, check whether the data to be processed exists.

In the Dexie.js DB database, you need to keep the method of each DB creation, in fact, by adding a Swtich case to complete each version update:

# dexie.js keep the DB database
db.version(1).stores({friends: "++id,name"});
db.version(2).stores({friends: "++id,name,shoeSize"});
db.version(3).stores({friends: "++id,shoeSize,firstName,lastName"}).upgrade(...)

# Internal principle, directly add switch case to complete version update
var dbPromise = idb.open('test-db7', 2, function(upgradeDb) {
  switch (upgradeDb.oldVersion) {
    case 0:
      upgradeDb.createObjectStore('store', {keyPath: 'name'});
    case 1:
      var peopleStore = upgradeDb.transaction.objectStore('store');
      peopleStore.createIndex('price'.'price'); }});Copy the code

It is also necessary to explicitly close the lower version of indexedDB when one page is opened but another page pulls new code to update it. The specific operation method is to listen to the onVersionchange event, when the version is upgraded, inform the current DB to shut down, and then update the operation in a new page.

openReq.onupgradeneeded = functionDb.createobjectstore (/*...) {// All other databases have been shut down. * /); db.onversionchange =function(event) {
    db.close();
  };

}  
  
Copy the code

Finally, there are a few caveats to the update:

  • Version updates cannot change the primary key
  • When you roll back code, be sure to check that the version has been updated. Otherwise, you can only update incrementally and change the version number to fix it.

Storage encryption feature

Sometimes, when we’re storing, we want a hash key generated by a String. How do we do that on the Web?

You can take advantage of WebCrypto, which is already available on the Web. To do this, you can use the Digest method. Here on MDN, there is a ready-made method, we can use directly.

Reference:

WebCrypto encryption means

Storage upper limit

The basic restrictions are:

The browser limit
Chrome Available space < 6%
Firebox Available space < 10%
Safari < 50MB
IE10 < 250MB

The expulsion strategy is as follows:

The browser Out of policy
Chrome Use the LRU policy after Chrome runs out of space
Firebox The LRU policy is used when the entire disk is full
Safari No out
Edge No out

Reference:

Store upper limit The browser kernel stores upper limit handling

Data indexing

In addition to basic CRUD in the database, an efficient index architecture is the top priority. There are three ways to index data in indexedDB:

  • Fixed key value
  • Index foreign key (index)
  • Cursor

Fixed key index

The IDBObjectStore gives us the ability to index data directly by primaryKey, see [code 1], which requires us to know the target key content from the start. Of course, it is also possible to index all data through getAll.

[code 1] [NewObject] IDBRequest get(any query); [NewObject] IDBRequest getKey(any query); [NewObject] IDBRequest getAll(optional any query, optional [EnforceRange] unsigned long count); [NewObject] IDBRequest getAllKeys(optional any query, optional [EnforceRange] unsigned long count);Copy the code

For example, we get a specific piece of data from primaryKey:

db.transaction("customers").objectStore("customers").get("id_card_1118899").onsuccess = function(event) {
    // data is event.target.result.name
};
Copy the code

You can also fetch data for the entire Object Store. These scenarios are less useful and will not be explained here. Let’s look at the way index is indexed.

The index index

If you want to query for some data, traversing the entire object directly can be very performance time-consuming. If we classify keys with index, we can quickly index the specified data. Here, we can directly use the index() method on IDBObjectStore to get the value of the specified index. For details, see [Code 1].

[code 1] IDBIndex index(DOMString name);Copy the code

This method returns an IDBIndex object directly. You can also think of this as a tiny index data content similar to ObjectStore. Next, we can use the get() method to get data for the specified index, see [Code 2].

Var index = objectStore.index("name");
index.get("Donna").onsuccess = function(event) {
  alert("Donna's SSN is " + event.target.result.ssn);
};
Copy the code

The get method returns only the first item regardless of whether your index is unique or not. If you want more than one data, you can use getAll(key). The corresponding value can be obtained directly from event.target.result.

objectStore.getAll().onsuccess = function(event) {
      printf(event.target.result); // Array
    };
Copy the code

In addition to getting all the data through getAll(), you can also iterate over the resulting data using a more efficient cursor method.

Reference:

GetAll () and openCursor instances

Index of the cursor

The so-called cursor, you should have a preliminary impression, just like the thing on our physical ruler, can move freely to identify the object content pointing to. There are two core methods inside a cursor:

  • Advance (count): Moves the current cursor position forward by the count position
  • Continue (key): moves the current cursor position to the specified key position, or to the next position if no key is provided.

For example, we use a cursor to walk over specific data in an Object Store.

objectStore.openCursor().onsuccess = function(event) {
    var cursor = event.target.result;
    if(cursor) {
        // cursor.key 
        // cursor.value
      cursor.continue();
    } else {
      console.log('Entries all displayed.'); }};Copy the code

In general, cursors can be used to iterate over two types of data, ObjectStore and Index.

  • Object.store: If a cursor is used on this Object, it will be based onprimaryKeyWalk through the data, and notice, there’s no duplication here, becauseprimaryKeyIt’s unique.
  • Index: If a cursor is used on an index, the current index will be traversed, and there may be duplication.

There are two ways to open a cursor on an IDBObjectStore object:

  • OpenCursor: Traversal objects are concrete data values, the most common method
  • OpenKeyCursor: Iterates over data keys

Here, we use openCursor to open an Index dataset directly and iterate through it.

PersonIndex.openCursor().onsuccess = function(event) {
  var cursor = event.target.result;
  if (cursor) {
    customers.push(cursor.value);
    cursor.continue();
  }
  else {
    alert("Got all customers: "+ customers); }};Copy the code

The cursor also provides an UPDATE and delete method that can be used to update data, otherwise the put method provided by ObjectStore is used directly.

Inside the cursor we can also define the scope and direction of its traversal. This is done directly in the openCursor() method, which has a constructor reference [code 1]. The cursor can pass in two parameters, the first to specify the range, and the second to specify the direction of movement of the cursor.

IDBRequest openCursor(optional any query, optional IDBCursorDirection direction ="next");
Copy the code

To set a range for a cursor, use the IDBKeyRange object, as shown in Listing 2. The key reference object in IDBKeyRange varies from user to user. For primaryKey if ObjectStore, and for current indexKey if Index

/ matches everything before "Bill", but does not need to include"Bill"
var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill".true);
Copy the code

For example, here we set an index range for PersonIndex, that is, a collection of data indexed between villainhr and jimmyVV.

# both include villainhr and jimmyVV data
var boundKeyRange = IDBKeyRange.bound("villainhr"."jimmyVV".true.true);

 PersonIndex.openCursor(boundKeyRange).onsuccess = function(event) {
  var cursor = event.target.result;
  if(cursor) { // Do something with the matches. cursor.continue(); }};Copy the code

If you also want to set the direction of the traversal and whether to exclude duplicate data, you can also set it according to the enumeration type of [Code 2]. For example, in [Code 3], we change the default cursor direction for traversing data to prev, starting at the end.

[代码2]
enum IDBCursorDirection {
  "next"."nextunique"."prev"."prevunique"}; [code 3] objectStore.opencurSOR (null, idBcursor.prev).onSuccess =function(event) {
  var cursor = event.target.result;
  if(cursor) { // cursor.value cursor.continue(); }};Copy the code

Transaction read performance

All reads and writes in indexDB are based on transaction. The transaction method in IDBDataBase is as follows [Code 1]. All reads and writes can be compared to requests in a transaction scope, where a transaction will not take effect until all requests have been completed, otherwise an exception or error will be thrown. Transaction is managed by listening for error, abort, and complete (see Code 2).

[NewObject] IDBTransaction Transaction ((DOMString or sequence<DOMString>) storeNames, optional IDBTransactionMode mode ="readonly"); [Code 2] Attribute EventHandler onabort; attribute EventHandler oncomplete; attribute EventHandler onerror;Copy the code

Such as:

var request = db.transaction(["customers"]."readwrite")
                .objectStore("customers")
                .delete("gg");
request.onsuccess = function(event) {
  // delete, done
};
Copy the code

You can manually pass in readwrite or any other readonly parameter to the transaction method to indicate what you want to do with the transaction. IndexedDB’s performance issues were determined at the time of its initial design.

Transactions in readonly mode can be executed concurrently. Transactions in write mode must be executed in queues

This means that if you use readwrite mode, subsequent transactions, whether readOnly or not, must wait for the transaction to complete.

The commonly used skill

Generates the primary key of id++

Specify primaryKey when generated, is passedcreateObjectStoreMethod to operate. Sometimes, we want to get a key directly and it exists in the current data set. We can add the key in optionskeyPathautoIncrementProperties. The key has a range of [1-], referenceSize of keyGenerator Key

db.createObjectStore('table1', {keyPath: 'id', autoIncrement: true});
Copy the code

recommended

Recommended reading

IndexedDB W3C document indexedDB introduction MDN indexedDB introduction

Easy library recommendation

Idb: A DB library for Promises

Indexed Appendix

  • An IndexedDB database stores data using key-value pairs. You can create an index on a property of an object for quick queries and enumeration sorts. .key can be a binary object
  • IndexedDB is a database in transaction mode. The IndexedDB API provides indexes, tables, Pointers, and so on, but all of these must be transaction dependent.
  • The IndexedDB API is essentially asynchronous.
  • IndexedDB database requests all contain onSuccess and ONError event attributes.
  • IndexedDB notifies the user through DOM events when the results are ready
  • IndexedDB is object-oriented. IndexedDB is not a relational database that represents collections in two-dimensional tables. This is very important and will influence how you design and build your application.
  • IndexedDB does not use structured query Language (SQL). It performs queries with cursors created by indexes, allowing you to iterate over the result set.
  • IndexedDB follows the same-origin policy

Limit and remove cases

  • Global multilingual hybrid storage. Internationalization support is poor. You have to deal with it yourself.
  • Synchronization with the server-side database. You’ll have to write your own synchronization code.
  • Full-text search.

A database may be purged under the following circumstances:

  • The user requested to clear data.
  • The browser is in private mode. When you finally exit the browser, the data is erased.
  • The capacity of storage devices such as hard disks reaches the upper limit.
  • incorrect
  • Incomplete change.

The conventional concept of

The database

  • Database: Usually contains one or more object stores. Each database must contain the following:

    • Name: Identifies the database in a particular source and remains constant throughout the life of the database. This name can be any string value, including an empty string.
    • Current version. When a database is first created, its version is 1 unless specified otherwise. Each database can have only one version at any time
  • Object Store: A partition used to hold data. Data is held permanently by object stores as key-value pairs. In the OS, you can create a key using a key generator and a key path.

    • Key generator: in simple terms, actively generate an id++ to distinguish each record when storing data. In this case, the data key is stored separately from the value, that is, out of line.
    • Key path: requires the user to take the initiative to set the key content for storing data.
    • Request: Each read/write operation can be regarded as a request.
    • Transaction: A collection of read and write requests.
    • Index: A special Object Store that indexes data from another Store.
  • Specific data key/value

    • Key: The value of this key can be generated in one of three ways. A key generator, a key path, user-specified value. Also, this key is unique in the current Object Store. A key can be string, date, float, and array. However, in older versions, only string or INTEGER was generally supported. (Now, the version should all be OK)
      • Key Generator: equivalent to a key generatorid++To generate a key value.
      • Key path: The current key can be specified according to the content in value. There can be some delimiters inside.
      • Specified key: This is where the user needs to specify the build manually.
    • Value: Stores Boolean, number, string, date, object, array, regEXP, undefined, and NULL. Files and blob objects can now also be stored.

Operational scope

  • Scope: This can be compared to the scope of a transaction, that is, the order in which a series of transactions are executed. This specifies that multiple Reading transactions can be executed simultaneously. But writing can only be done in a queue.
  • Key range: Sets the contents of the range of keys used to fetch data.

Reference:

The original concept IndexedDB

IDBFactory

This is actually the object mounted on indexDB. The main apis are as follows:

[Exposed=(Window,Worker)]
interface IDBFactory {
  [NewObject] IDBOpenDBRequest open(DOMString name,
                                    optional [EnforceRange] unsigned long long version);
  [NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);

  short cmp(any first, any second);
};
Copy the code

You can open a database directly through Open. Callback to result listener by returning a Request object:

var request = indexedDB.open('AddressBook', 15);
request.onsuccess = function(evt) {... }; request.onerror =function(evt) {... };Copy the code

Reference:

IndexDB Factory API

IDBRequest

When you’re done with the open method, you get a Request callback object. So this is an instance of IDBRequest.

[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
  readonlyattribute any result; // Open the IDBObjectStore instancereadonly attribute DOMException? error;
  readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
  readonly attribute IDBTransaction? transaction;
  readonly attribute IDBRequestReadyState readyState;

  // Event handlers:
  attribute EventHandler onsuccess;
  attribute EventHandler onerror;
};

enum IDBRequestReadyState {
  "pending"."done"
};

[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
  // Event handlers:
  attribute EventHandler onblocked;
  attribute EventHandler onupgradeneeded;
};
Copy the code

You can use result to get the result of the current database operation. You also need to listen onupgradeneneeded event to do this if you open the updated version number. The most common error encountered with indexeddb. open is a VER_ERR version error. This indicates that the version of the database stored on disk is higher than the version you are trying to open.

db.onerror = function(event) {
  // Generic error handler for all errors targeted at this database's // requests! alert("Database error: " + event.target.errorCode); };Copy the code

So, normally when creating IndexDB you need to also manage the update operation of its version, which needs to listen onupgradeneneeded to be implemented.

request.onupgradeneeded = function(event) {// Update the object storage space and index.... };Copy the code

Or we can use the IDB microlibrary directly for the read operation.

  var dbPromise = idb.open('test-db3', 1, function(upgradeDb) {
    if(! upgradeDb.objectStoreNames.contains('people')) {
      upgradeDb.createObjectStore('people', {keyPath: 'email'});
    }
    if(! upgradeDb.objectStoreNames.contains('notes')) {
      upgradeDb.createObjectStore('notes', {autoIncrement: true});
    }
    if(! upgradeDb.objectStoreNames.contains('logs')) {
      upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement: true}); }});Copy the code

The event. Result obtained through the onupgradeneneeded callback is an instance of IDBDatabase, which is often used to set indexes and insert data. See below.

Reference:

IDBRequest API

IDBDatabase

This Object is often used for Object Store and transaction creation and deletion. This section is the event.target.result object obtained by onupgradenneeded event:

request.onupgradeneeded = function(event) {// Update the object storage space and index.... // event.target.result object};Copy the code

The specific API content is as follows:

[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
  readonly attribute DOMString name;
  readonly attribute unsigned long long version;
  readonly attribute DOMStringList objectStoreNames;

  [NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
                                         optional IDBTransactionMode mode = "readonly");
  void close();

  [NewObject] IDBObjectStore createObjectStore(DOMString name,
                                               optional IDBObjectStoreParameters options);
  void deleteObjectStore(DOMString name);

  // Event handlers:
  attribute EventHandler onabort;
  attribute EventHandler onclose;
  attribute EventHandler onerror;
  attribute EventHandler onversionchange;
};

dictionary IDBObjectStoreParameters {
  (DOMString or sequence<DOMString>)? keyPath = null;
  boolean autoIncrement = false;
};
Copy the code

If it passes the createObjectStore method, the result is an IDBObjectStore instance object. If it is a transaction method, it is an IDBTransaction object.

IDBObjectStore

This object is used to create indexes and insert data.

For reference:

[Exposed=(Window,Worker)]
interface IDBObjectStore {
  attribute DOMString name;
  readonly attribute any keyPath;
  readonly attribute DOMStringList indexNames;
  [SameObject] readonly attribute IDBTransaction transaction;
  readonly attribute boolean autoIncrement;

  [NewObject] IDBRequest put(any value, optional any key);
  [NewObject] IDBRequest add(any value, optional any key);
  [NewObject] IDBRequest delete(any query);
  [NewObject] IDBRequest clear();
  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any query,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any query,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");

  IDBIndex index(DOMString name);

  [NewObject] IDBIndex createIndex(DOMString name,
                                   (DOMString or sequence<DOMString>) keyPath,
                                   optional IDBIndexParameters options);
  void deleteIndex(DOMString name);
};

dictionary IDBIndexParameters {
  boolean unique = false;
  boolean multiEntry = false;
};
Copy the code

IDBIndex

This object is used to Index the operation object, there will also be get and getAll methods. The details are as follows:

[Exposed=(Window,Worker)]
interface IDBIndex {
  attribute DOMString name;
  [SameObject] readonly attribute IDBObjectStore objectStore;
  readonly attribute any keyPath;
  readonly attribute boolean multiEntry;
  readonly attribute boolean unique;

  [NewObject] IDBRequest get(any query);
  [NewObject] IDBRequest getKey(any query);
  [NewObject] IDBRequest getAll(optional any query,
                                optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest getAllKeys(optional any query,
                                    optional [EnforceRange] unsigned long count);
  [NewObject] IDBRequest count(optional any query);

  [NewObject] IDBRequest openCursor(optional any query,
                                    optional IDBCursorDirection direction = "next");
  [NewObject] IDBRequest openKeyCursor(optional any query,
                                       optional IDBCursorDirection direction = "next");
};
Copy the code

Reference:

Indexeddb IndexedDB indexedDB