本章内容
cookie
浏览器存储API
IndexedDB
可能出现的面试题:
1.了解过cookie吗?
2.了解过localStorage和sessionStorage吗?
3.了解过IndexDB吗?
HTTP cookie通常也叫作cookie ,最初用于在客户端存储会话信息。这个规范要求服务器在响应HTTP请求时,通过发送Set-Cookie HTTP头部包含会话信息。
这个HTTP响应会设置一个名为"name" ,值为"value" 的cookie。
知识点:
限制
cookie是与特定域绑定的。不被其他域访问
不超过300个cookie;
每个cookie不超过4096字节;
每个域不超过20个cookie;
每个域不超过81 920字节。
每个域能设置的cookie总数也是受限的,但不同浏览器的限制不同。例如:
最新版IE和Edge限制每个域不超过50个cookie;
最新版Firefox限制每个域不超过150个cookie;
最新版Opera限制每个域不超过180个cookie;
Safari和Chrome对每个域的cookie数没有硬性限制。
2.cookie的构成
名称 :唯一标识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则不会。
这些参数在Set-Cookie 头部中使用分号加空格隔开,比如:
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
对www.wrox.com及其他wrox.com的子域
安全标志secure是cookie中唯一的非名/值对,只需一个secure 就可以了。比如:
HTTP/1.1 200 OK
Content-type: text/html
Set-Cookie: name=value; domain=.wrox.com; path=/; secure
Other-header: other-header-value
3.JavaScript中的cookie
在JavaScript中处理cookie比较麻烦,因为接口过于简单,只有BOM的document.cookie 属性。
所有名和值都是URL编码的,因此必须使用decodeURIComponent()解码。
4.子cookie
为绕过浏览器对每个域cookie数的限制,有些开发者提出了子cookie 的概念。子cookie是在单个cookie存储的小块数据,本质上是使用cookie的值在单个cookie中存储多个名/值对。最用的子cookie模式如下:
name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5
4.还有一种叫作HTTP-only 的cookie。HTTP-only可以在浏览器设置,也可以在服务器设置,但只能在服务器上读取,这是因为JavaScript无法取得这种cookie的值。
5.Web Storage
localStorage 和sessionStorage
Storage 的实例与其他对象一样,但增加了以下方法。
clear() :删除所有值;不在Firefox中实现。
getItem(name ) :取得给定 name 的值。
key(index ) :取得给定数值位置的名称。
removeItem(name ) :删除给定 name 的名/值对。
setItem(name , value ) :设置给定 name 的值。
sessionStorage 对象
sessionStorage 对象只存储会话数据,这意味着数据只会存储到浏览器关闭。这跟浏览器关闭时会消失的会话cookie类似。存储
在sessionStorage 中的数据不受页面刷新影响,可以在浏览器崩溃并重启后恢复。
sessionStorage 对象是Storage 的实例
localStorage 对象
在修订的HTML5规范里,localStorage 对象取代了globalStorage,作为在客户端持久存储数据的机制。要访问同一个localStorage 对象,页面必须来自同一个域(子域不可以)、在相同的端口上使用相同的协议。
localStorage 是Storage 的实例
// 使用方法存储数据
localStorage.setItem("name", "Nicholas");
// 使用属性存储数据
localStorage.book = "Professional JavaScript";
// 使用方法取得数据
let name = localStorage.getItem("name");
// 使用属性取得数据
let book = localStorage.book;
6.存储事件
使用属性或setItem() 设置值、使用delete 或removeItem() 删除值,以及每次调用clear() 时都会触发这个事件。这个事件的事件对象有如下4个属性。
domain :存储变化对应的域。
key :被设置或删除的键。
newValue :键被设置的新值,若键被删除则为null 。
oldValue :键变化之前的值。
window.addEventListener("storage",
(event) => alert('Storage changed for ${event.domain}'));
7.IndexedDB
Indexed Database API简称IndexedDB ,是浏览器中存储结构化数据的一个方案。
使用IndexedDB数据库的第一步是调用indexedDB.open()方法,并给它传入一个要打开的数据库名称。如果给定名称的数据库已存在,则会发送一个打开它的请求;如果不存在,则会发送创建并打开这个数据库的请求。这个方法会返回IDBRequest 的实例,可以在这个实例上添加onerror 和onsuccess 事件处理程序。
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;
};
对象存储
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" });
};
事务
创建了对象存储之后,剩下的所有操作都是通过事务 完成的。事务要通过调用数据库对象的transaction() 方法创建。任何时候,只要想要读取或修改数据,都要通过事务把所有修改操作组织起来。最简单的情况下,可以像下面这样创建事务:
let transaction = db.transaction();
如果不指定参数,则对数据库中所有的对象存储有只读权限。更具体的方式是指定一个或多个要访问的对象存储的名称:
let transaction = db.transaction("users");
这样可以确保在事务期间只加载users 对象存储的信息。如果想要访问多个对象存储,可以给第一个参数传入一个字符串数组:
let transaction = db.transaction(["users", "anotherStore"]);
要修改访问模式,可以传入第二个参数。这个参数应该是下列三个字符串之一:“readonly”、“readwrite"或"versionchange” 。比如:
let transaction = db.transaction("users", "readwrite");
有了事务的引用,就可以使用objectStore() 方法并传入对象存储的名称以访问特定的对象存储。然后,可以使用add() 和put() 方法添加和更新对象,使用get() 取得对象,使用delete() 删除对象,使用clear() 删除所有对象。
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);
因为一个事务可以完成任意多个请求,所以事务对象本身也有事件处理程序:onerror 和oncomplete 。这两个事件可以用来获取事务级的状态信息:
transaction.onerror = (event) => {
// 整个事务被取消
};
transaction.oncomplete = (event) => {
// 整个事务成功完成
};
add() 或put()
// users是一个用户数据的数组
let request,
requests = [];
for (let user of users) {
request = store.add(user);
request.onerror = () => {
// 处理错误
};
request.onsuccess = () => {
// 处理成功
};
requests.push(request);
}
通过游标查询
使用事务可以通过一个已知键取得一条记录。如果想取得多条数据,则需要在事务中创建一个游标 。游标是一个指向结果集的指针。
需要在对象存储上调用openCursor() 方法创建游标。
const transaction = db.transaction("users"),
store = transaction.objectStore("users"),
request = store.openCursor();
request.onsuccess = (event) => {
// 处理成功
};
request.onerror = (event) => {
// 处理错误
};
这个IDBCursor 实例有几个属性。direction :字符串常量,表示游标的前进方向以及是否应该遍历所有重复的值。可能的值包括:
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)}`);
}
};
这个例子中的cursor.value 保存着实际的对象。正因为如此,在显示它之前才需要使用JSON来编码。
其他关于indexDB略,要用再看,感觉和后台关系更大。