JavaScript Advanced Programming Fourth Edition Learning-Chapter 25


title: JavaScript Advanced Programming Fourth Edition Learning-Chapter 25
date: 2021-5-31 15:06:04
author: Xilong88
tags: JavaScript

The content of this chapter
cookie
browser storage API
IndexedDB
may appear interview questions:
1. Have you understood cookies?
2. Have you learned about localStorage and sessionStorage?
3. Know IndexDB?

HTTP cookies are often called cookies, and were originally used to store session information on the client. This specification requires the server to include session information by sending the Set-Cookie HTTP header when responding to an HTTP request.

This HTTP response will set a cookie named "name" with a value of "value".

Knowledge points:

Restrict
cookies are bound to specific domains. Not accessed by other domains

不超过300个cookie;
每个cookie不超过4096字节;
每个域不超过20个cookie;
每个域不超过81 920字节。

The total number of cookies that can be set for each domain is also limited, but different browsers have different restrictions. E.g:

最新版IE和Edge限制每个域不超过50个cookie;
最新版Firefox限制每个域不超过150个cookie;
最新版Opera限制每个域不超过180个cookie;
Safari和Chrome对每个域的cookie数没有硬性限制。

2. The composition of cookies

名称 :唯一标识cookie的名称。cookie名不区分大小写,因
此myCookie 和MyCookie 是同一个名称。不过,实践中最好将
cookie名当成区分大小写来对待,因为一些服务器软件可能这样对
待它们。cookie名必须经过URL编码。
值 :存储在cookie里的字符串值。这个值必须经过URL编码。
域 :cookie有效的域。发送到这个域的所有请求都会包含对应的
cookie。这个值可能包含子域(如www.wrox.com),也可以不包含
(如.wrox.com表示对wrox.com的所有子域都有效)。如果不明确
设置,则默认为设置cookie的域。
路径 :请求URL中包含这个路径才会把cookie发送到服务器。例
如,可以指定cookie只能由http://www.wrox.com/books/访问,因此
访问http://www.wrox.com/下的页面就不会发送cookie,即使请求的
是同一个域。
过期时间 :表示何时删除cookie的时间戳(即什么时间之后就不发
送到服务器了)。默认情况下,浏览器会话结束后会删除所有
cookie。不过,也可以设置删除cookie的时间。这个值是GMT格式
(Wdy, DD-Mon-YYYY HH:MM:SS GMT),用于指定删除cookie
的具体时间。这样即使关闭浏览器cookie也会保留在用户机器上。
把过期时间设置为过去的时间会立即删除cookie。
安全标志 :设置之后,只在使用SSL安全连接的情况下才会把
cookie发送到服务器。例如,请求https://www.wrox.com会发送
cookie,而请求http://www.wrox.com则不会。

These parameters are separated by semicolons and spaces in the header of Set-Cookie, for example:

HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; expires=Mon, 22-Jan-07 07:10:24 GMT; domain=.wrox.com
Other-header: other-header-value

For www.wrox.com and other subdomains of wrox.com

The security symbol secure is the only unnamed/value pair in the cookie, and only one secure is required. such as:

HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; domain=.wrox.com; path=/; secure
Other-header: other-header-value

3. Cookies in JavaScript

It is troublesome to process cookies in JavaScript, because the interface is too simple, only the document.cookie property of the BOM.

All names and values ​​are URL-encoded, so they must be decoded using decodeURIComponent().

4. Child cookie

In order to bypass the browser limit on the number of cookies per domain, some developers have proposed the concept of sub-cookies. A child cookie is a small piece of data stored in a single cookie, essentially using the value of the cookie to store multiple name/value pairs in a single cookie. The most used sub-cookie modes are as follows:

name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5

4. There is also a cookie called HTTP-only. HTTP-only can be set on the browser or on the server, but it can only be read on the server. This is because JavaScript cannot obtain the value of this cookie.

5.Web Storage

localStorage and sessionStorage

The instance of Storage is the same as other objects, but the following methods are added.

clear() :删除所有值;不在Firefox中实现。
getItem(name ) :取得给定 name 的值。
key(index ) :取得给定数值位置的名称。
removeItem(name ) :删除给定 name 的名/值对。
setItem(name , value ) :设置给定 name 的值。

sessionStorage object

The sessionStorage object only stores session data, which means that the data will only be stored until the browser is closed. This is similar to a session cookie that disappears when the browser is closed. The data stored
in sessionStorage is not affected by page refresh and can be restored after the browser crashes and restarts.

The sessionStorage object is an instance of Storage

localStorage object

In the revised HTML5 specification, the localStorage object replaces globalStorage as a mechanism for persistently storing data on the client side. To access the same localStorage object, the page must come from the same domain (subdomains are not allowed) and use the same protocol on the same port.

localStorage is an instance of Storage

// 使用方法存储数据
localStorage.setItem("name", "Nicholas");
// 使用属性存储数据
localStorage.book = "Professional JavaScript";
// 使用方法取得数据
let name = localStorage.getItem("name");
// 使用属性取得数据
let book = localStorage.book;

6. Store events

Use properties or setItem() to set values, use delete or removeItem() to delete values, and this event is triggered every time clear() is called. The event object of this event has the following 4 properties.

domain :存储变化对应的域。
key :被设置或删除的键。
newValue :键被设置的新值,若键被删除则为null 。
oldValue :键变化之前的值。
window.addEventListener("storage",
    (event) => alert('Storage changed for ${event.domain}'));

7. IndexedDB

Indexed Database API is referred to as IndexedDB, which is a solution for storing structured data in the browser.

The first step to use the IndexedDB database is to call the indexedDB.open() method and pass in the name of the database to be opened. If the database with the given name already exists, a request to open it will be sent; if it does not exist, a request to create and open the database will be sent. This method will return an instance of IDBRequest, and onerror and onsuccess event handlers can be added to this instance.
let db,
    request,
    version = 1;
request = indexedDB.open("admin", version);
request.onerror = (event) =>
  alert(`Failed to open: ${event.target.errorCode}`);
request.onsuccess = (event) => {
  db = event.target.result;
};

Object storage

let user = {
  username: "007",
  firstName: "James",
  lastName: "Bond",
  password: "foo"
};
request.onupgradeneeded = (event) => {
  const db = event.target.result;

  // 如果存在则删除当前objectStore。测试的时候可以这样做
  // 但这样会在每次执行事件处理程序时删除已有数据
  if (db.objectStoreNames.contains("users")) {
    db.deleteObjectStore("users");
  }
  db.createObjectStore("users", { keyPath: "username" });
};

Affairs

After the object store is created, all remaining operations are completed through transactions. The transaction is created by calling the transaction() method of the database object. At any time, as long as you want to read or modify data, you must organize all modification operations through transactions. In the simplest case, you can create a transaction like this:

let transaction = db.transaction();

If you do not specify parameters, you have read-only access to all object stores in the database. A more specific way is to specify the name of one or more object stores to be accessed:

let transaction = db.transaction("users");

This ensures that only the information stored in the users object is loaded during the transaction. If you want to access multiple object stores, you can pass an array of strings to the first parameter:

let transaction = db.transaction(["users", "anotherStore"]);

To modify the access mode, you can pass in the second parameter. This parameter should be one of the following three strings: "readonly", "readwrite" or "versionchange". such as:

let transaction = db.transaction("users", "readwrite");

With the transaction reference, you can use the objectStore() method and pass in the name of the object store to access a specific object store. Then, you can use add() and put() methods to add and update objects, get() to get objects, delete() to delete objects, and clear() to delete all objects.

const transaction = db.transaction("users"),
    store = transaction.objectStore("users"),
    request = store.get("007");
request.onerror = (event) => alert("Did not get the object!");
request.onsuccess = (event) => alert(event.target.result.firstName);

Because a transaction can complete any number of requests, the transaction object itself also has event handlers: onerror and oncomplete. These two events can be used to obtain transaction-level status information:

transaction.onerror = (event) => {
  // 整个事务被取消
};
transaction.oncomplete = (event) => {
  // 整个事务成功完成
};

add() or put()

// users是一个用户数据的数组
let request,
    requests = [];
for (let user of users) {
  request = store.add(user);
  request.onerror = () => {
    // 处理错误
  };
  request.onsuccess = () => {
    // 处理成功
  };
  requests.push(request);
}

Query by cursor

Using transactions, a record can be obtained through a known key. If you want to get multiple pieces of data, you need to create a cursor in the transaction. The cursor is a pointer to the result set.

You need to call the openCursor() method on the object store to create a cursor.

const transaction = db.transaction("users"),

    store = transaction.objectStore("users"),
    request = store.openCursor();
request.onsuccess = (event) => {
  // 处理成功
};
request.onerror = (event) => {
  // 处理错误
};

This IDBCursor instance has several properties. direction: A string constant indicating the direction of the cursor and whether it should traverse all repeated values. Possible values ​​include:

NEXT("next")
、NEXTUNIQUE("nextunique") 、PREV("prev")
、PREVUNIQUE("prevunique") 。
key :对象的键。
value :实际的对象。
primaryKey :游标使用的键。可能是对象键或索引键(稍后讨
论)。
request.onsuccess = (event) => {
  const cursor = event.target.result;
  if (cursor) { // 永远要检查
    console.log(`Key: ${cursor.key}, Value: ${JSON.stringify(cursor.value)}`);
  }
};

The cursor.value in this example holds the actual object. Because of this, it needs to be encoded with JSON before displaying it.

Others about indexDB, you have to use it and then look at it, it feels more related to the background.