This is the 9th day of my participation in the November Gwen Challenge. See details: The Last Gwen Challenge 2021.

Prior to HTML5, application data could only be stored in cookies and would be included in every server request. Unlike cookies, browser local storage is much more limited (at least 5MB) and the information is not transferred to the server. The local stores in this article include localStorage, Web SQL Database, and IndexedDB.

localStorage

The size of localStorage supported by common browsers is 5M. The size of localStorage varies with browsers.

Localstorage has two apis: localStorage and sessionStorage, which exist in the window object: LocalStorage corresponds to window.localStorage and sessionStorage corresponds to window.sessionStorage.

The difference between localStorage and sessionStorage mainly lies in its lifetime. LocalStorage is a permanent storage, while sessionStorage when the session ends, the key value pairs in sessionStorage will be cleared.

Localstorage is a standard key-value pair (KV for short) data type, simple and easy to expand, as long as you want to store the object in localstorage in some encoding way into a string, it can be easily supported.

Due to the security policy of the browser, localstorage cannot be cross-domain, nor can the sub-domain inherit the localstorage data of the parent domain name.

In terms of usage, the sessionStorage and localStorage methods are the same.

Initialize the

Use it in a browser to check compatibility and whether the browser supports it.

If (! LocalStorage){alert(" Browser supports localStorage "); return false; }Copy the code

Data store operation

The method of writing data is to add a property directly to window.localstorage, such as window.localstorage. a or window.localstorage [“b”]. Its read, write and delete operations are very simple, in the form of key-value pairs, as follows:

const storage=window.localStorage; Storage ["a"]=1; Storage. B =1; SetItem ("c",3); console.log(typeof storage["a"]); console.log(typeof storage["b"]); console.log(typeof storage["c"]); storage.getItem("a");Copy the code

After running the re-development tool, you can see:

SetItem () is recommended for writing data, getItem() for reading data, and removeItem() for clearing key/value pairs. If you want to clear all key-value pairs at once, use clear(). In addition, HTML5 provides a key() method, which can be used when the key value is not known, as follows:

const storage = window.localStorage; function showStorage(){ for(var i=0; i<storage.length; Console. log(storage.key(I)+ ":" + storage.getitem (I)) + "<br>"); }}Copy the code

It should be noted that HTML5 local storage can only store strings, any format of storage will be automatically converted to strings, so when reading, you need to do their own type conversion.

For json data side storage, you need to call json.stringify () to convert it to a string before storing it, and call json.parse () to convert the string to JSON format after reading it.

Storage events

Events can listen for changes in key/value pairs using the following methods:

if(window.addEventListener){ window.addEventListener("storage",handle_storage,false); }else if(window.attachEvent){ window.attachEvent("onstorage",handle_storage); } function handle_storage(e){ if(! e){e=window.event; } // logic}Copy the code

For event variable E, is a StorageEvent object, which provides some useful properties to observe key-value pair changes, as shown in the following table:

Property Type Description
target EventTarget Event target (maximum target in DOM tree)
type DOMString Types of events
bubbles Boolean Whether the event is usually a bubble
cancelable Boolean Whether the event can be cancelled
key DOMString (string) Key changes
oldValue DOMString (string) Old value of key being changed
newValue DOMString (string) Changing the new value of the key
url DOMString (string) The address of the document changed by the key
storageArea Storage Affected storage objects

Web SQL Database

The Web SQL Database is virtually obsolete

Although Html5 already provides powerful localStorage and sessionStorage, both of them only provide data for storing simple data structures, not data for complex Web applications. Unfortunately, Html5 provides a browser-side database support, allowing direct access to JavaScript APIS in the browser to create a local database, and support standard SQL CRUD operations, so that offline Web applications are more convenient to store structured data. Next, we’ll look at local data apis and usage.

  • The first step:openDatabaseMethod: Create an object that accesses the database.
  • Step 2: Execute using the database access object created in the first steptransactionMethod, which allows you to set up an event response method that starts the transaction successfully, where SQL can be executed.
  • Step 3: PassexecuteSqlMethod to perform a query, which of course can be:CRUD.

The openDatabase method


The first call is to create the database, and then to establish the connection.

Const dataBase = openDatabase("student", "1.0", "student table ", 1024 * 1024, function () {}); // Const dataBase = openDatabase("student", "1.0", "student table ", function () {});Copy the code

The openDatabase method opens an existing database and creates a database if it doesn’t already exist. The meanings of several parameters are as follows:

  1. Database name.
  2. The version number of the database, for now, it is ok to pass a 1.0, of course, can not fill;
  3. Description of the database.
  4. Sets the size (KB) of the allocated database.
  5. Callback function (can be omitted).

The db.transaction method sets up a callback function that accepts an argument that is the object of the transaction we started. This object can then be used to execute the Sql script, combined with the following steps.

Execute queries using the executeSql method

ts.executeSql(sqlQuery,[value1,value2..] ,dataHandler,errorHandler)Copy the code

Parameter Description:

  • qlQuery: Indicates the SQL statement to be executedcreate,select,update,delete;
  • [value1,value2..]: An array of all parameters used in the SQL statement, inexecuteSqlIn the method, wills>The parameter to be used in the statement starts with a? Replace, and then place these parameters in sequence as an array in the second parameter
  • dataHandler: Success is the callback function called to get the query result set.
  • errorHandler: callback function to call when execution fails;

IndexedDB

Web Storage (Local Storage and Session Storage) and IndexedDB. Web Storage uses simple string key-value pairs to store data locally, which is convenient and flexible. However, it is difficult to store a large amount of structured data. IndexedDB is designed to store a large amount of structured data on the client side and use an API for efficient index retrieval.

Asynchronous API


Most of the operations in IndexedDB are not in the usual call method, return result mode, but in the request-response mode, such as open database operations

const request=window.indexedDB.open('testDB');
Copy the code

Instead of returning a handle to a DB object, we get an IDBOpenDBRequest object, and the DB object we want is in its Result property

The response to this directive request is an IDBDatabase object, which is the IndexedDB object

In addition to result, the IDBOpenDBRequest interface defines several important attributes

  • onerror: Callback function handle to which the request failed
  • onsuccess: Handle to the callback function that requested success
  • onupgradeneeded: Handle to request database version changes

The asynchronous API means that we can use Request. result to fetch an indexedDB object before the instruction is finished. Just like with Ajax, the object is not retrieved when the statement is finished, so we usually handle it in its callback function.

Creating a database

The previous statement showed how to open an indexedDB database. An indexedDB can be created or opened by calling the indexeddb. open method. Look at a complete process

function openDB(name) { const request = window.indexedDB.open(name); request.onerror = function (e) { console.log("OPen Error!" ); }; request.onsuccess = function (e) { myDB.db = e.target.result; }; } const myDB = { name: "test", version: 1, db: null, }; openDB(myDB.name);Copy the code

MyDB: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db: mydb.db

version

We note that in addition to onError and onSuccess, IDBOpenDBRequest has a callback function like handle, onupgradenneeded. This handle is called when the version number of the database we requested to open is inconsistent with that of an existing database.

The indexeddb.open () method also has a second optional argument, the database version number. The default version number when the database is created is 1. Onupgradenneeded needs to be called when the passed version number does not match the current version of the database. Otherwise, it’s called onError, so let’s change the example

function openDB (name,version) {
    const version=version || 1;
    const request=window.indexedDB.open(name,version);
    request.onerror=function(e){
        console.log(e.currentTarget.error.message);
    };
    request.onsuccess=function(e){
        myDB.db=e.target.result;
    };
    request.onupgradeneeded=function(e){
        console.log('DB version changed to '+version);
    };
} 
const myDB={
    name:'test',
    version:3,
    db:null
};
openDB(myDB.name,myDB.version);
Copy the code

Since you have just created a database of version 1, when you open a database of version 3, the console will output: DB version changed to 3

Close or delete the database

To close a database, call the close method of the database object directly

function closeDB(db){
    db.close();
}
Copy the code

Delete the database using the deleteDatabase method of the indexedDB object

function deleteDB(name){
    indexedDB.deleteDatabase(name);
}
Copy the code

A simple call

const myDB={ name:'test', version:3, db:null }; openDB(myDB.name,myDB.version); setTimeout(function(){ closeDB(myDB.db); deleteDB(myDB.name); }, 500);Copy the code

Since the asynchronous API is not guaranteed to get the DB object before the closeDB method is called (actually getting the DB object is also much slower than executing a statement), setTimeout is used to delay the call. Note, of course, that each indexedDB instance has a handle to the onClose callback function to handle when the database is shut down.

object store

When we have a database, we naturally want to create a table to store data, but there is no concept of table in indexedDB. Instead, objectStore is objectStore. A database can contain multiple ObjectStores. That is, an objectStore is like a table in which each piece of data stored is associated with a key.

A specified field in each record can be used as a key value (keyPath), an automatically generated increasing number can be used as a key value (keyGenerator), or no value can be specified. The data structure that objectStore can store varies depending on the type of select key

Key type Store the data
Do not use Any value, but the key argument needs to be specified each time a piece of data is added
keyPath Javascript object that must have a property as a key value
keyGenerator Any value
All use A JavaScript object that does not generate a new key value if it has a keyPath specified property, or populates the keyPath specified property if it does not automatically generate an increment key value
The transaction

Before you can do anything with the new database, you need to start a transaction. You need to specify which Object Stores the transaction spans.

Transactions have three modes

  • Read only:read, cannot modify database data and can be executed concurrently
  • Reading and writing:readwrite, can be read and write operations
  • Version change:verionchange
const transaction=db.transaction([students','taecher']); // Open a transaction with students and teacher object store const objectStore= transaction.objectstore (' Students '); // Get the Students Object StoreCopy the code
Add data to the Object Store

An ObjectStore is created by calling the createObjectStore method of a database instance. The method takes two arguments: store name and key type. Call store’s Add method to add data. With this in mind, you can now add data to the Object Store

keyPath

Because all operations on new data need to be done in a TRANSACTION which requires an Object Store to be specified, it needs to be initialized only at database creation time for later use, which is an important part of onupgradeneneeded. Let’s change the code

function openDB (name,version) { const version=version || 1; const request=window.indexedDB.open(name,version); request.onerror=function(e){ console.log(e.currentTarget.error.message); }; request.onsuccess=function(e){ myDB.db=e.target.result; }; request.onupgradeneeded=function(e){ const db=e.target.result; if(! db.objectStoreNames.contains('students')){ db.createObjectStore('students',{keyPath:"id"}); } console.log('DB version changed to '+version); }; }Copy the code

This adds an Object store named STUDENTS to the database when it is created, and prepares some data to be added

const students=[{ 
    id:1001, 
    name:"Byron", 
    age:24 
},{ 
    id:1002, 
    name:"Frank", 
    age:30 
},{
    id:1003, 
    name:"Aaron", 
    age:26 
}];
Copy the code
function addData(db,storeName){ const transaction=db.transaction(storeName,'readwrite'); const store=transaction.objectStore(storeName); for(var i=0; i<students.length; i++){ store.add(students[i]); } } openDB(myDB.name,myDB.version); setTimeout(function(){ addData(myDB.db,'students'); }, 1000);Copy the code

This adds three records to the Students Object Store, with id as the key, to see the effect on the Chrome console

keyGenerate
function openDB (name,version) { const version=version || 1; const request=window.indexedDB.open(name,version); request.onerror=function(e){ console.log(e.currentTarget.error.message); }; request.onsuccess=function(e){ myDB.db=e.target.result; }; request.onupgradeneeded=function(e){ const db=e.target.result; if(! db.objectStoreNames.contains('students')){ db.createObjectStore('students',{autoIncrement: true}); } console.log('DB version changed to '+version); }; }Copy the code

To find the data

You can call the get method of the Object Store to retrieve data by keys, using keyPath as an example:

function getDataByKey(db,storeName,value){
    const transaction=db.transaction(storeName,'readwrite'); 
    const store=transaction.objectStore(storeName); 
    const request=store.get(value); 
    request.onsuccess=function(e){ 
        var student=e.target.result; 
        console.log(student.name); 
    };
}
Copy the code
Update the data

You can call the PUT method of the Object Store to update data. Records with the same key value are automatically replaced to update data. If they do not have the same key value, records can be added

function updateDataByKey(db, storeName, value) {
    const transaction = db.transaction(storeName, "readwrite");
    const store = transaction.objectStore(storeName);
    const request = store.get(value);
    request.onsuccess = function (e) {
        const student = e.target.result;
        student.age = 35;
        store.put(student);
    };
}
Copy the code
Delete data and object Store

Call the Object Store’s delete method to delete the record based on the key value

function deleteDataByKey(db, storeName, value) {
    const transaction = db.transaction(storeName, "readwrite");
    const store = transaction.objectStore(storeName);
    store.delete(value);
}
Copy the code

To clear the Object Store, call the Object Store clear method

function clearObjectStore(db, storeName) {
    const transaction = db.transaction(storeName, "readwrite");
    const store = transaction.objectStore(storeName);
    store.clear();
}
Copy the code

The deleteObjectStore method that calls a database instance to delete an ObjectStore needs to be called within onupgradenneeded

if (db.objectStoreNames.contains("students")) {
    db.deleteObjectStore("students");
}
Copy the code
Create indexes

CreateIndex (createIndex); createIndex (createIndex);

  • The index name
  • Index property field name
  • Whether the index attribute value is unique
function openDB(name, version) { const version = version || 1; const request = window.indexedDB.open(name, version); request.onerror = function (e) { console.log(e.currentTarget.error.message); }; request.onsuccess = function (e) { myDB.db = e.target.result; }; request.onupgradeneeded = function (e) { const db = e.target.result; if (! db.objectStoreNames.contains("students")) { const store = db.createObjectStore("students", { keyPath: "id" }); store.createIndex("nameIndex", "name", { unique: true }); store.createIndex("ageIndex", "age", { unique: false }); } console.log("DB version changed to " + version); }; }Copy the code
Use indexes to retrieve data
function getDataByIndex(db, storeName) {
    const transaction = db.transaction(storeName);
    const store = transaction.objectStore(storeName);
    const index = store.index("nameIndex");
    index.get("Byron").onsuccess = function (e) {
        const student = e.target.result;
        console.log(student.id);
    };
}
Copy the code

The name index is unique, but the age index only gets the first value. To get all values that match the age condition, you need to use the cursor

The cursor

Using indexes and cursors in indexedDB is inseparable. If you have cursors in the Object Store, you can use cursors to traverse the Object Store.

Open the cursor using the Object Store openCursor() method

function fetchStoreByCursor(db, storeName) { const transaction = db.transaction(storeName); const store = transaction.objectStore(storeName); const request = store.openCursor(); request.onsuccess = function (e) { const cursor = e.target.result; if (cursor) { console.log(cursor.key); const currentStudent = cursor.value; console.log(currentStudent.name); cursor.continue(); }}; }Copy the code

Curson.contine () moves the cursor down until no data is returned from undefined

Index combines with the cursor

To get student with age 26, use the index in conjunction with the cursor

function getMultipleData(db, storeName) { const transaction = db.transaction(storeName); const store = transaction.objectStore(storeName); const index = store.index("ageIndex"); const request = index.openCursor(IDBKeyRange.only(26)); request.onsuccess = function (e) { const cursor = e.target.result; if (cursor) { const student = cursor.value; console.log(student.id); cursor.continue(); }}; }Copy the code

We can use the index to open a cursor, as described below. We can also use the index.openKeyCursor() method to retrieve only the key value of each object.

Specifies the cursor range

The index.opencursor ()/index.openKeyCursor() method retrieves all records of the Object Store without passing an argument. As in the example above, we can filter the search.

You can use the key range to limit the range of values in the cursor, passing it to openCursor() or openKeyCursor() as the first argument.

  • IDBKeyRange.only(value): Only the specified data is obtained
  • IDBKeyRange.lowerBound(value,isOpen): Gets the minimum yesvalueThe second parameter indicates whether to excludevalueThe value itself, in mathematics, is an open interval
  • IDBKeyRange.upperBound(value,isOpen): similar to the above, used to get data whose maximum value is value
  • IDBKeyRange.bound(value1,value2,isOpen1,isOpen2): There is no need to explain

Get student whose name starts with a letter in b-e

function getMultipleData(db, storeName) { const transaction = db.transaction(storeName); const store = transaction.objectStore(storeName); const index = store.index("nameIndex"); const request = index.openCursor(IDBKeyRange.bound("B", "F", false, true)); request.onsuccess = function (e) { const cursor = e.target.result; if (cursor) { const student = cursor.value; console.log(student.name); cursor.continue(); }}; }Copy the code

After the