Use the HTML5 IndexedDB API, html5indexeddb

Source: Internet
Author: User
Tags createindex

[Switch] Use HTML5 IndexedDB API, html5indexeddb

Local data persistence improves Web application accessibility and mobile application response capabilities

The index database (IndexedDB) API (as part of HTML5) is useful for creating a data-intensive offline HTML5 Web application with rich local storage data. It also helps to cache data locally and enable traditional online Web applications (such as mobile Web applications) to run and respond faster. This article describes how to manage the IndexedDB database.

 

An important feature of HTML5 is local data persistence, which enables users to access Web applications online and offline. In addition, local data persistence makes mobile applications more sensitive, uses less bandwidth, and can work more efficiently in low-bandwidth scenarios. HTML5 provides some local data persistence options. The first option islocalstorageIt allows you to use a simple key-value pair to store data. IndexedDB (a more powerful option) allows you to store a large number of objects locally and use a robust data access mechanism to retrieve data.

The IndexedDB API replaces the Web Storage API, which is not recommended in the HTML5 specification. (However, some leading browsers still support Web Storage, including Apple's Safari and Opera Web browsers). Compared with Web Storage, IndexedDB has multiple advantages, this includes indexing, transaction processing, and robust query functions. This article uses a series of examples to demonstrate how to manage the IndexedDB database. (See the download section to obtain the complete source code of the example .)

Important Concepts

A website may have one or more IndexedDB databases. Each database must have a unique name.

A database can contain one or moreObject Storage Service. An object storage service (uniquely identified by a name) is a set of records. Each record hasKeyAnd oneValue. This value is an object that can have one or more attributes. A key may be derived from a key path or explicitly set based on a key generator. A key generator automatically generates a unique continuous positive integer. The Key Path defines the key value path. It can be a single JavaScript identifier or multiple identifiers separated by periods.

The specification contains an asynchronous API and a synchronous API. Synchronous API is used in Web browsers. Asynchronous APIs use requests and callbacks.

In the following example, the output is appended toresultOfdivMark. To updateresultElement, which can be cleared and set during each data operationinnerHTMLAttribute. Each sample JavaScript function is composed ofonclickEvent call.

Handling errors or exceptions and debugging

All asynchronous requests have oneonsuccessCallback andonerrorCallback. The former is called when the database operation is successful, and the latter is called when the operation is not successful. Listing 1 isonerrorCallback example.

List 1. asynchronous error handling functions
request.onerror = function(e) {   // handle error   ...   console.log("Database error: " + e.target.errorCode);};

Use JavaScript when using the IndexedDB APItry/catchBlock is a good idea. This function is useful for handling errors and exceptions that may occur before database operations, such as attempting to read or operate data when the database is not opened, or try to write data when another read/write transaction is opened.

IndexedDB is difficult to debug and troubleshoot, because in many cases, error messages are extensive and lack information value. You can useconsole.logAnd JavaScript debugging Tools, such as Firebug for Mozilla Firefox or Developer Tools built in Chrome. The value of these tools is immeasurable for any JavaScript-intensive application, especially for HTML5 applications that use the IndexedDB API.

 

Back to Top

Use Database

A database can only have one version at a time. When you create a database for the first time, its initial version number is 0. After a database is created, the database (and its object storage) can only be calledversionchangeTo change. To change a database after it is created, you must open a database with a later version. This operation will triggerupgradeneededEvent. The code for modifying the database or object storage service must be locatedupgradeneededIn the event processing function.

The code segment in Listing 2 shows how to create a database: CallopenMethod and pass the database name. If a database with the specified name does not exist, the database is created.

List 2. Create a new database
function createDatabase() {   var openRequest = localDatabase.indexedDB.open(dbName);   openRequest.onerror = function(e) {      console.log("Database error: " + e.target.errorCode);   };   openRequest.onsuccess = function(event) {      console.log("Database created");      localDatabase.db = openRequest.result;   };   openRequest.onupgradeneeded = function (evt) {         ...   };}

To delete an existing database, you can calldeleteDatabaseMethod, and pass the name of the database to be deleted, as shown in listing 3.

Listing 3. Deleting an existing database
function deleteDatabase() {   var deleteDbRequest = localDatabase.indexedDB.deleteDatabase(dbName);   deleteDbRequest.onsuccess = function (event) {      // database deleted successfully   };   deleteDbRequest.onerror = function (e) {      console.log("Database error: " + e.target.errorCode);   };}

The code segment in Listing 4 shows how to connect to an existing database.

Listing 4. Open the latest database version
function openDatabase() {   var openRequest = localDatabase.indexedDB.open("dbName");   openRequest.onerror = function(e) {      console.log("Database error: " + e.target.errorCode);   };   openRequest.onsuccess = function(event) {      localDatabase.db = openRequest.result;   };}

It is so easy to create, delete, and open databases. Now it is time to use OSS.

 

Back to Top

Use OSS

OSS is a collection of data records. To create a new object storage service in an existing database, you must perform version control on the existing database. To do this, open the database for version control. Besides the Database Name,openThe method also accepts the version number as the second parameter. To create a new version of the database (that is, to create or modify an Object Storage Service), you only need to open a database with a higher version of the existing database. This will callonupgradeneededEvent processing functions.

To create an object storage service, you can call it on a database object.createObjectStoreMethod, as shown in listing 5.

Listing 5. Create an Object Storage Service
function createObjectStore() {   var openRequest = localDatabase.indexedDB.open(dbName, 2);   openRequest.onerror = function(e) {      console.log("Database error: " + e.target.errorCode);   };   openRequest.onsuccess = function(event) {      localDatabase.db = openRequest.result;   };   openRequest.onupgradeneeded = function (evt) {      var employeeStore = evt.currentTarget.result.createObjectStore         ("employees", {keyPath: "id"});   };}

We have learned how OSS works. Next, let's take a lookIndexHow to reference object storage that contains data.

 

Back to Top

Use Index

In addition to using keys to retrieve records in Oss, you can also use indexed fields to retrieve records. OSS can have one or more indexes. An index is a special object storage service that references object storage that contains data. It is automatically updated when you modify the referenced Object Storage Service (that is, when you add, modify, or delete a record.

To create an index, you must use the method shown in listing 5 to control the database version. Indexes can be unique or not unique. The unique index requires that all values in the index be unique, for example, using an email address field. When a value can be repeated, you need to use a non-unique index, such as a city, state, or country. The code segment in Listing 6 shows how to create a non-unique index on the state field of the employee object and create a non-unique index on the ZIP code field, create a unique index in the email address field:

Listing 6. Creating an index
function createIndex() {   var openRequest = localDatabase.indexedDB.open(dbName, 2);   openRequest.onerror = function(e) {      console.log("Database error: " + e.target.errorCode);   };   openRequest.onsuccess = function(event) {      db = openRequest.result;   };   openRequest.onupgradeneeded = function (evt) {     var employeeStore = evt.currentTarget.result.objectStore("employees");     employeeStore.createIndex("stateIndex", "state", { unique: false });     employeeStore.createIndex("emailIndex", "email", { unique: true });     employeeStore.createIndex("zipCodeIndex", "zip_code", { unique: false })   };}

Next, you will use transactions to perform some operations on OSS.

 

Back to Top

Use transactions

You need to use transactions to perform all read and write operations on OSS. Similar to the working principle of transactions in relational databases, IndexedDB transactions provide an atomic set of database write operations. This set is either completely committed or completely not committed. IndexedDB transactions also have a tool for stopping and committing database operations.

Table 1 lists and describes the transaction modes provided by IndexedDB.

Table 1. IndexedDB transaction mode
Mode Description
readonly Provides read-only access to an object storage service, which is used when querying object storage service.
readwrite Provides read and write access to an object storage service.
versionchange Provides read and write access to modify the definition of OSS, or creates a new OSS.

The default transaction mode isreadonly. You can enable multiple concurrentreadonlyTransaction, but only onereadwriteTransaction. For this reason, you can only use this function when updating data.readwriteTransaction. Independent (indicating that no other concurrent transactions can be opened)versionchangeTransactions operate on a database or object storage service. You canonupgradeneededUsed in event processing functionsversionchangeCreate, modify, or delete an Object Storage Service (OSS), or add an index to OSS.

ToreadwriteInemployeesTo create a transaction in Oss, you can use the following statement:var transaction = db.transaction("employees", "readwrite");.

The JavaScript function in listing 7 shows how to use a transaction to retrieve data using keys.employeesA specific employee record in Oss.

Listing 7. Using keys to obtain a specific record
function fetchEmployee() {try {   var result = document.getElementById("result");   result.innerHTML = "";   if (localDatabase != null && localDatabase.db != null) {     var store = localDatabase.db.transaction("employees").objectStore("employees");     store.get("E3").onsuccess = function(event) {      var employee = event.target.result;      if (employee == null) {         result.value = "employee not found";      }      else {         var jsonStr = JSON.stringify(employee);         result.innerHTML = jsonStr;      }     };   }}catch(e){   console.log(e);}}

The JavaScript function in listing 8 shows how to use a transaction to useemailIndexIndex Instead of object storage key for retrievalemployeesSpecific employee records in Oss.

Listing 8. Using indexes to retrieve specific records
function fetchEmployeeByEmail() {try {   var result = document.getElementById("result");   result.innerHTML = "";   if (localDatabase != null && localDatabase.db != null) {      var range = IDBKeyRange.only("john.adams@somedomain.com");      var store = localDatabase.db.transaction("employees").objectStore("employees");      var index = store.index("emailIndex");      index.get(range).onsuccess = function(evt) {         var employee = evt.target.result;         var jsonStr = JSON.stringify(employee);         result.innerHTML = jsonStr;      };   }}catch(e){

Listing 9 usesreadwriteAn example of creating a new employee record for a transaction.

Listing 9. Create a new employee record
function addEmployee() {   try {      var result = document.getElementById("result");      result.innerHTML = "";      var transaction = localDatabase.db.transaction("employees", "readwrite");      var store = transaction.objectStore("employees");      if (localDatabase != null && localDatabase.db != null) {         var request = store.add({            "id": "E5",            "first_name" : "Jane",            "last_name" : "Doh",            "email" : "jane.doh@somedomain.com",            "street" : "123 Pennsylvania Avenue",            "city" : "Washington D.C.",            "state" : "DC",            "zip_code" : "20500",         });         request.onsuccess = function(e) {           result.innerHTML = "Employee record was added successfully.";         };         request.onerror = function(e) {            console.log(e.value);            result.innerHTML = "Employee record was not added.";         };      }   }   catch(e){      console.log(e);   }}

In listing 10readwriteAn example of updating existing employee records for transactions. In this example, the record ID is changedE3The email address of the employee.

Listing 10. update existing employee records
function updateEmployee() {try {   var result = document.getElementById("result");   result.innerHTML = "";   var transaction = localDatabase.db.transaction("employees", "readwrite");   var store = transaction.objectStore("employees");   var jsonStr;   var employee;   if (localDatabase != null && localDatabase.db != null) {      store.get("E3").onsuccess = function(event) {         employee = event.target.result;         // save old value         jsonStr = "OLD: " + JSON.stringify(employee);         result.innerHTML = jsonStr;         // update record         employee.email = "john.adams@anotherdomain.com";         var request = store.put(employee);         request.onsuccess = function(e) {            console.log("Added Employee");         };         request.onerror = function(e) {            console.log(e.value);         };         // fetch record again         store.get("E3").onsuccess = function(event) {            employee = event.target.result;            jsonStr = "
NEW: " + JSON.stringify(employee); result.innerHTML = result.innerHTML + jsonStr; }; // fetch employee again }; // fetch employee first time }}catch(e){ console.log(e);}}

Listing 11 shows how to create or delete all records in Oss.readwriteExample of a transaction. Like other asynchronous transactions,clearTransactions are called based on whether the object storage service has been cleared.onsuccessOronerrorCallback.

Listing 11. Clearing OSS transactions
function clearAllEmployees() {try {   var result = document.getElementById("result");   result.innerHTML = "";   if (localDatabase != null && localDatabase.db != null) {     var store = localDatabase.db.transaction("employees", "readwrite").objectStore("employees");     store.clear().onsuccess = function(event) {      result.innerHTML = "'Employees' object store cleared";     };   }}catch(e){   console.log(e);}}

These examples demonstrate some common uses of transactions. Next, you will see how the IndexedDB dashboard works.

 

Back to Top

Use cursor

Similar to the method in which the midstream mark of a relational database works, the cursor in IndexedDB enables you to iterate records in an object storage service. You can also use OSS indexes to iterate records. The cursor in IndexedDB is bidirectional, so you can iterate records forward and backward, and you can skip duplicate records in non-unique indexes.openCursorMethod To open a cursor. It accepts two optional parameters, including the range and direction.

Listing 12 isemployeesOSS opens a cursor and iterates all employee records.

Listing 12. iterate all employee records
function fetchAllEmployees() {try {   var result = document.getElementById("result");   result.innerHTML = "";   if (localDatabase != null && localDatabase.db != null) {      var store = localDatabase.db.transaction("employees").objectStore("employees");      var request = store.openCursor();      request.onsuccess = function(evt) {         var cursor = evt.target.result;         if (cursor) {            var employee = cursor.value;            var jsonStr = JSON.stringify(employee);            result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; }}catch(e){ console.log(e);}}

The following example uses the cursor for the index. Table 2 lists and describes the range types or filters provided by the IndexedDB API when a cursor is opened for an index.

Table 2. Range types or filters provided by the IndexedDB API when a cursor is opened for an index
Range type or filter Description
IDBKeyRange.bound Returns all records within the specified range. This range has a lower boundary and an upper boundary. It also has two optional parameters:lowerOpenAndupperOpenThe two parameters indicate whether the records at the bottom or upper boundary should be included in the range.
IDBKeyRange.lowerBound All records that exceed the specified boundary value range. This range has an optional parameterlowerOpenIndicates whether the records in the following world should be included in the range.
IDBKeyRange.upperBound Returns all records before the specified boundary value. It also has an optionalupperOpenParameters.
IDBKeyRange.only Only records that match the specified value are returned.

Listing 13 is a basic example of iterating all employee records in a particular country. This query is the most common. It enables you to retrieve all records that match a specific condition. This example usesstateIndexAndIDBKeyRange.onlyRange, returns and specifies the value (in this example"New York") All matched records.

Listing 13. iterate over all employee records in New York City.
function fetchNewYorkEmployees() {try {   var result = document.getElementById("result");   result.innerHTML = "";   if (localDatabase != null && localDatabase.db != null) {      var range = IDBKeyRange.only("New York");      var store = localDatabase.db.transaction("employees").objectStore("employees");      var index = store.index("stateIndex");      index.openCursor(range).onsuccess = function(evt) {         var cursor = evt.target.result;         if (cursor) {            var employee = cursor.value;            var jsonStr = JSON.stringify(employee);            result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; }}catch(e){ console.log(e);}}

Listing 14 is a usageIDBKeyRange.lowerBoundRange example. It iterates over 92000 of all employees.

Listing 14. Use IDBKeyRange.lowerBound
function fetchEmployeeByZipCode1() {try {   var result = document.getElementById("result");   result.innerHTML = "";   if (localDatabase != null && localDatabase.db != null) {     var store = localDatabase.db.transaction("employees").objectStore("employees");     var index = store.index("zipIndex");     var range = IDBKeyRange.lowerBound("92000");     index.openCursor(range).onsuccess = function(evt) {      var cursor = evt.target.result;      if (cursor) {         var employee = cursor.value;         var jsonStr = JSON.stringify(employee);         result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; }}catch(e){ console.log(e);}}

Listing 15 is a usageIDBKeyRange.upperBoundRange example. It iterates the zip code based on 93000 of all employees.

Listing 15. Use IDBKeyRange.upperBound
function fetchEmployeeByZipCode2() {try {   var result = document.getElementById("result");   result.innerHTML = "";   if (localDatabase != null && localDatabase.db != null) {     var store = localDatabase.db.transaction("employees").objectStore("employees");     var index = store.index("zipIndex");     var range = IDBKeyRange.upperBound("93000");     index.openCursor(range).onsuccess = function(evt) {      var cursor = evt.target.result;      if (cursor) {         var employee = cursor.value;         var jsonStr = JSON.stringify(employee);         result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; }}catch(e){ console.log(e);}}

Listing 16 is a usageIDBKeyRange.boundRange example. It retrieves all employees whose zip code value is between 92000 and 92999.

Listing 16. Use IDBKeyRange.bound
function fetchEmployeeByZipCode3() {try {   var result = document.getElementById("result");   result.innerHTML = "";   if (localDatabase != null && localDatabase.db != null) {     var store = localDatabase.db.transaction("employees").objectStore("employees");     var index = store.index("zipIndex");     var range = IDBKeyRange.bound("92000", "92999", true, true);     index.openCursor(range).onsuccess = function(evt) {      var cursor = evt.target.result;      if (cursor) {         var employee = cursor.value;         var jsonStr = JSON.stringify(employee);         result.innerHTML = result.innerHTML + "
" + jsonStr; cursor.continue(); } }; }}catch(e){ console.log(e);}}

These examples show that the cursor function in IndexedDB is similar to that in relational databases. You can use IndexedDB cursor to iterate records in an object storage service and an index record in an object storage service. The cursor in IndexedDB is bidirectional, which provides additional flexibility.

 

Back to Top

Conclusion

The IndexedDB API is very powerful. You can use it to create data-intensive applications (especially offline HTML5 Web applications) with rich local data storage ). You can also use the IndexedDB API to cache data locally so that traditional online Web applications (especially mobile Web applications) can run and respond faster, this eliminates the need to retrieve data from the Web server each time. For example, you can cache the selected data in the IndexedDB database.

This document describes how to manage an IndexedDB database, including creating a database, deleting a database, and establishing a connection to the database. This article also shows many more advanced functions of the IndexedDB API, including transaction processing, index, and cursor. You can use these concepts to build offline applications or mobile Web applications that utilize IndexedDB APIs.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.