文章目录

  • 简介
  • IndexedDB简介
  • IndexedDB的使用
    • IndexedDB的浏览器支持
    • 创建IndexedDB
    • indexdb中的CURD
    • 使用游标cursor

简介

IndexedDB是一种在浏览器端存储数据的方式。既然称之为DB,是因为它丰富了客户端的查询方式,并且因为是本地存储,可以有效的减少网络对页面数据的影响。

有了IndexedDB,浏览器可以存储更多的数据,从而丰富了浏览器端的应用类型。

IndexedDB简介

IndexedDB和传统的关系型数据不同的是,它是一个key-value型的数据库。

value可以是复杂的结构体对象,key可以是对象的某些属性值也可以是其他的对象(包括二进制对象)。你可以使用对象中的任何属性做为index,以加快查找。

IndexedDB是自带transaction的,所有的数据库操作都会绑定到特定的事务上,并且这些事务是自动提交了,IndexedDB并不支持手动提交事务。

IndexedDB API大部分都是异步的,在使用异步方法的时候,API不会立马返回要查询的数据,而是返回一个callback。

异步API的本质是向数据库发送一个操作请求,当操作完成的时候,会收到一个DOM event,通过该event,我们会知道操作是否成功,并且获得操作的结果。

IndexedDB是一种 NoSQL 数据库,和关系型数据库不同的是,IndexedDB是面向对象的,它存储的是Javascript对象。

IndexedDB还有一个很重要的特点是其同源策略,每个源都会关联到不同的数据库集合,不同源是不允许访问其他源的数据库,从而保证了IndexedDB的安全性。

IndexedDB的使用

这一节,我们将会以具体的例子来讲解如何使用IndexedDB。

IndexedDB的浏览器支持

不同的浏览器对于IndexedDB有不同的实现,正常来说,我们可以使用window.indexedDB来获取到浏览器的indexedDB对象。但是对于某些浏览器来说,还没有使用标准的window.indexedDB,而是用带前缀的实现。

所以我们在使用过程中通常需要进行判断和转换:

// In the following line, you should include the prefixes of implementations you want to test.
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
// DON'T use "var indexedDB = ..." if you're not in a function.
// Moreover, you may need references to some window.IDB* objects:
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction || {READ_WRITE: "readwrite"}; // This line should only be needed if it is needed to support the object's constants for older browsers
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
// (Mozilla has never prefixed these objects, so we don't need window.mozIDB*)

上面我们从window获取了indexedDB,IDBTransaction和IDBKeyRange三个对象。

其中indexedDB表示的是数据库的连接。IDBTransaction表示的是transaction,而IDBKeyRange则是用从数据库的某个特定key range中取出数据。

但是,通常来说带前缀的实现一般都是不稳定的,所以我们通常不建议在正式环境中使用,所以如果不支持标准表达式的话,需要直接报错:

if (!window.indexedDB) {console.log("Your browser doesn't support a stable version of IndexedDB. Such and such feature will not be available.");
}

创建IndexedDB

要使用IndexedDB,我们首先需要open it:

// Let us open our database
var request = window.indexedDB.open("MyTestDatabase", 3);

open方法返回一个IDBOpenDBRequest对象,同时这是一个异步操作,open操作并不会立马打开数据库或者开启事务,我们可以通过监听request的事件来进行相应的处理。

open方法传入两个参数,第一个参数是数据库的名字,第二个参数是数据库的版本号。

当你创建一个新的数据库或者升级一个现有的数据库版本的时候,将会触发一个onupgradeneeded事件,并在事件中传入IDBVersionChangeEvent,我们可以通过event.target.result来获取到IDBDatabase对象,然后通过这个对象来进行数据库的版本升级操作。如下所示:

// This event is only implemented in recent browsers
request.onupgradeneeded = function(event) { // Save the IDBDatabase interface var db = event.target.result;// Create an objectStore for this databasevar objectStore = db.createObjectStore("name", { keyPath: "myKey" });
};

注意,这里的版本号是一个整数。如果你传入一个float,那么将会对该float进行取整操作。

有了request,我们可以通过监听onerror或者onsuccess事件来进行相应的处理。

var db;
var request = indexedDB.open("MyTestDatabase");
request.onerror = function(event) {console.log("Why didn't you allow my web app to use IndexedDB?!");
};
request.onsuccess = function(event) {db = event.target.result;
};

拿到db对象之后,我们可以设置全局的异常处理:

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

IndexedDB中的table叫做object stores,和关系型数据库中的table一样,object stores中的每一个对象都和一个key相关联,和key相关的有两个概念 key path 和 key generator.

如果存储的是javascript Object对象,那么可以指定该对象中的某一个属性作为key path,那么这个属性将会被作为key。

如果没有指定key path,那么存储的Object可以是任何对象,甚至是基础类型比如数字和String。

而key generator就是key的生成器。

假如我们想要存储这样的数据:

// This is what our customer data looks like.
const customerData = [{ ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },{ ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" }
];

看一下对应的数据库操作是怎么样的:

const dbName = "the_name";var request = indexedDB.open(dbName, 2);request.onerror = function(event) {// Handle errors.
};
request.onupgradeneeded = function(event) {var db = event.target.result;// Create an objectStore to hold information about our customers. We're// going to use "ssn" as our key path because it's guaranteed to be// unique - or at least that's what I was told during the kickoff meeting.var objectStore = db.createObjectStore("customers", { keyPath: "ssn" });// Create an index to search customers by name. We may have duplicates// so we can't use a unique index.objectStore.createIndex("name", "name", { unique: false });// Create an index to search customers by email. We want to ensure that// no two customers have the same email, so use a unique index.objectStore.createIndex("email", "email", { unique: true });// Use transaction oncomplete to make sure the objectStore creation is // finished before adding data into it.objectStore.transaction.oncomplete = function(event) {// Store values in the newly created objectStore.var customerObjectStore = db.transaction("customers", "readwrite").objectStore("customers");customerData.forEach(function(customer) {customerObjectStore.add(customer);});};
};

我们需要在onupgradeneeded事件中处理所有的schema相关的操作。

首先使用db.createObjectStore创建了一个customers的ObjectStore,并且使用了对象的keypath作为key。

除了key之外,我们创建了两个index,以提高查询速度。

最后我们监听transaction.oncomplete事件,并在里面加入存储object的操作。

上面的代码中,我们使用了keyPath作为key。

下面是一个使用key Generator的例子:

 var objStore = db.createObjectStore("names", { autoIncrement : true });

indexdb中的CURD

indexedDB的所有操作都需要在事务中,我们看一个开启事务的操作:

var transaction = db.transaction(["customers"], "readwrite");

上面的例子中使用readwrite来操作customers ObjectStore。

transaction接收两个参数,第一个参数是一个数组,数组中是这个trans中将会处理的ObjectStores,第二个参数是处理的模式。

有了transaction之后,我们可以监听事务的complete和error操作,然后就可以进行add操作了:

// Do something when all the data is added to the database.
transaction.oncomplete = function(event) {console.log("All done!");
};transaction.onerror = function(event) {// Don't forget to handle errors!
};var objectStore = transaction.objectStore("customers");
customerData.forEach(function(customer) {var request = objectStore.add(customer);request.onsuccess = function(event) {// event.target.result === customer.ssn;};
});

上面的例子中,我们使用了add方法,add的前提是数据库中并不存在相同key的对象。除了add方法之外,我们还可以使用put方法,put方法主要用来进行更新操作。

再看一个删除的操作:

var request = db.transaction(["customers"], "readwrite").objectStore("customers").delete("444-44-4444");
request.onsuccess = function(event) {// It's gone!
};

现在我们的数据库已经有了数据,我们看下怎么进行查询:

var transaction = db.transaction(["customers"]);
var objectStore = transaction.objectStore("customers");
var request = objectStore.get("444-44-4444");
request.onerror = function(event) {// Handle errors!
};
request.onsuccess = function(event) {// Do something with the request.result!console.log("Name for SSN 444-44-4444 is " + request.result.name);

这里,我们直接使用了db.transaction,默认情况下是readonly模式的。

下面是一个更新的例子:

var objectStore = db.transaction(["customers"], "readwrite").objectStore("customers");
var request = objectStore.get("444-44-4444");
request.onerror = function(event) {// Handle errors!
};
request.onsuccess = function(event) {// Get the old value that we want to updatevar data = event.target.result;// update the value(s) in the object that you want to changedata.age = 42;// Put this updated object back into the database.var requestUpdate = objectStore.put(data);requestUpdate.onerror = function(event) {// Do something with the error};requestUpdate.onsuccess = function(event) {// Success - the data is updated!};
};

更新我们使用的是put方法。

使用游标cursor

indexedDB支持游标操作,我们可以使用cursor来遍历objectStore的数据:

var objectStore = db.transaction("customers").objectStore("customers");objectStore.openCursor().onsuccess = function(event) {var cursor = event.target.result;if (cursor) {console.log("Name for SSN " + cursor.key + " is " + cursor.value.name);cursor.continue();}else {console.log("No more entries!");}
};

openCursor可以接受多个参数,第一个参数可以接受key的查询范围,第二个参数用来指定遍历的方向。如果两个参数都为空的话,默认是所有的数据的以升序的顺序遍历。

如果想遍历下一个游标,则可以调用cursor.continue。

我们看一下两个参数的游标使用:

// Only match "Donna"
var singleKeyRange = IDBKeyRange.only("Donna");// Match anything past "Bill", including "Bill"
var lowerBoundKeyRange = IDBKeyRange.lowerBound("Bill");// Match anything past "Bill", but don't include "Bill"
var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound("Bill", true);// Match anything up to, but not including, "Donna"
var upperBoundOpenKeyRange = IDBKeyRange.upperBound("Donna", true);// Match anything between "Bill" and "Donna", but not including "Donna"
var boundKeyRange = IDBKeyRange.bound("Bill", "Donna", false, true);// To use one of the key ranges, pass it in as the first argument of openCursor()/openKeyCursor()
index.openCursor(boundKeyRange, "prev").onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// Do something with the matches.cursor.continue();}
};

除了openCursor,我们还可以通过使用openKeyCursor来遍历KeyCursor:

// Using a normal cursor to grab whole customer record objects
index.openCursor().onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// cursor.key is a name, like "Bill", and cursor.value is the whole object.console.log("Name: " + cursor.key + ", SSN: " + cursor.value.ssn + ", email: " + cursor.value.email);cursor.continue();}
};// Using a key cursor to grab customer record object keys
index.openKeyCursor().onsuccess = function(event) {var cursor = event.target.result;if (cursor) {// cursor.key is a name, like "Bill", and cursor.value is the SSN.// No way to directly get the rest of the stored object.console.log("Name: " + cursor.key + ", SSN: " + cursor.primaryKey);cursor.continue();}
};

除此之外,我们还可以直接通过index来进行查询:

var index = objectStore.index("name");index.get("Donna").onsuccess = function(event) {console.log("Donna's SSN is " + event.target.result.ssn);
};

要使用index的前提就是需要在request.onupgradeneeded中创建index。

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/indexeddb-kickoff/

本文来源:flydean的博客

欢迎关注我的公众号:「程序那些事」最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

IndexedDB详解相关推荐

  1. web存储详解(cookie、sessionStorage、localStorage、indexedDB)

    目录 一.web存储概念简介 1. 什么是web存储? 2. 为什么需要web存储? 二.web存储详解 1. cookie 2. sessionStorage和localStorage (1). 相 ...

  2. Sentry For Vue 完整接入详解(2021 Sentry v21.8.x)前方高能预警!三万字,慎入!

    内容源于:https://docs.sentry.io/platforms/javascript/guides/vue/ 系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创 ...

  3. 【面试题】详解Cookie、localStorage、sessionStorage区别

    [面试题]详解Cookie.localStorage.sessionStorage区别 三者基本概念 Cookie localStorage sessionStorage 安全性的考虑 Cookie. ...

  4. 跨域详解!前后端分离解决跨域问题

    文章目录 一.为什么会出现跨域问题 二.什么是跨域 三.非同源限制 四.跨域问题的解决方式 Jsonp前后端配合 前端修改 后端修改 CORS 详解响应头 5. SpringBoot解决 [方式一]全 ...

  5. 详解Javascript本地存储的方式、区别及应用场景

    详解Javascript本地存储的方式.区别及应用场景 一.方式 javaScript本地缓存的方法我们主要讲述以下四种: cookie sessionStorage localStorage ind ...

  6. 从命令行到IDE,版本管理工具Git详解(远程仓库创建+命令行讲解+IDEA集成使用)

    首先,Git已经并不只是GitHub,而是所有基于Git的平台,只要在你的电脑上面下载了Git,你就可以通过Git去管理"基于Git的平台"上的代码,常用的平台有GitHub.Gi ...

  7. JVM年轻代,老年代,永久代详解​​​​​​​

    秉承不重复造轮子的原则,查看印象笔记分享连接↓↓↓↓ 传送门:JVM年轻代,老年代,永久代详解 速读摘要 最近被问到了这个问题,解释的不是很清晰,有一些概念略微模糊,在此进行整理和记录,分享给大家.在 ...

  8. docker常用命令详解

    docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...

  9. 通俗易懂word2vec详解词嵌入-深度学习

    https://blog.csdn.net/just_so_so_fnc/article/details/103304995 skip-gram 原理没看完 https://blog.csdn.net ...

最新文章

  1. 如何用Python和深度神经网络识别图像?
  2. Science公布2021年度十大科学突破,AI这项前所未有的突破上榜
  3. hexo+githup搭建属于自己的博客
  4. javase(Properties集合及学生对象信息录入文本中案例)
  5. 第六章:系统困境之 你的努力与时代进程相逆
  6. centos利用nexus搭建局域网docker私有仓库
  7. 【英语学习】【Level 07】U06 First Time L1 My very first trip
  8. MySQL三种打开方式
  9. PostgreSQL 9.6 同步多副本 与 remote_apply事务同步级别 应用场景分析
  10. 【渝粤教育】国家开放大学2018年春季 0314-21T兽医基础 参考试题
  11. 前缀无歧义编码(PFC)
  12. R语言画好看的聚类树
  13. 网银爬虫系统(爬取网银流水,爬取网银余额)难点分析
  14. 为什么学习嵌入式会搞单片机以及如何学习C51单片机
  15. storm风暴英雄 tempo_风暴英雄Tempo Storm 安娜版本天梯环境速报 安娜强度居T3
  16. BeatSaber节奏光剑插件开发官方教程2-简单的插件示例
  17. java七行情书_七行情书
  18. 【网络攻击手段之----- DDOS攻击】
  19. 百度编辑器 百度编辑器
  20. 【身份证识别】基于matlab GUI BP神经网络身份证识别【含Matlab源码 2239期】

热门文章

  1. 算法的数值稳定性实验报告用c语言,数值计算实验教案.doc
  2. 【C 语言小游戏】手打贪吃蛇1,闭关在家37天“吃透”这份345页PDF
  3. ISO认证证书上常见的认可标志
  4. 为什么建议大家使用 Linux 开发!
  5. 大学生必备的十大网站有哪些?
  6. Tello无人机版之使用Scratch2和ROS进行机器人图形化编程学习
  7. 浪潮之巅 “八叛徒”与硅谷
  8. linux boot分区创建,Linux 更换 Boot分区 磁盘 示例
  9. Revit二次开发—获取内置参数对应的中文字符串,并导出Excel;举例(BuiltParameterGroup、ParameterType和BuiltInCategory)
  10. 2022年磺化工艺考试练习题及模拟考试