目录
起因:在网速慢,需要加载的文件很大(大于5M),每次刷新界面都要重新加载的情况。选择把文件存在浏览器的indexedDB数据库中,在存储后,以后再刷新界面,从本地的数据库中提取,就不用每次加载了。
(如果是打开本地的文件,上传到数据库,网上有很多成熟的方案)
参考文献:http://www.ruanyifeng.com/blog/2018/07/indexeddb.html
https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API
https://developer.mozilla.org/zh-CN/docs/Web/API/IndexedDB_API/Using_IndexedDB
读取文件:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
目标:在数据库存入2个文件 一个是js文件,主键就是js ; 另一个是个xml文件,主键就是xml
一. 打开数据库
先定义变量
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB;
var request = indexedDB.open("opencv",1);
var db;
open这个动作,如果以前没有这个数据库,就会新建数据库,
如果有数据库,就打开,
如果有数据库,但版本改变,就会执行升级,
open接受2个参数,数据库名 和 版本号,版本号可以不写,不写的话,第一次版本默认是1
二. 在数据库中创建一个对象仓库
打开数据库就像任何其他操作一样 — 你必须进行 "request"。
open 请求不会立即打开数据库或者开始一个事务。 对 open()
函数的调用会返回一个我们可以作为事件来处理的包含 result(成功的话)或者错误值的 IDBOpenDBRequest
对象。在 IndexedDB 中的大部分异步方法做的都是同样的事情 - 返回一个包含 result 或错误的 IDBRequest
对象。open 函数的结果是一个 IDBDatabase
对象的实例。
返回结果有4中情况 onupgradeneeded(更新)、onsuccess(成功)、onerror(失败)、onblocked(被阻塞)
(1). 更新
在第一次新建数据库时,版本不写会默认是1,版本从无到有,也算是版本更新。
当版本改变,也会触发更新。
在第一次新建数据库后,第一个步骤是新建表,如果是再次更新时,就要判断数据库中有没有这个表,如果没有就新建表。
① 新建表 'oc'
② 如果是再次更新,表存在,就删除表中的数据。
删除数据的方法delete()
request.onupgradeneeded = function (event) {
console.log('数据库更新');
db = event.target.result;
var objectStore;
if (!db.objectStoreNames.contains('oc')) {
console.log("新建表");
objectStore = db.createObjectStore('oc');
}else{
console.log("版本更新,数据删除更新");
var t = event.target.transaction;
var requ = t.objectStore('oc').delete("js");
var requ2 = t.objectStore('oc').delete("xml");
requ.onsuccess = function (event) { console.log('数据库表数据js删除成功'); };
requ.onerror = function (event) { console.log('数据库表数据js删除成功'); };
requ2.onsuccess = function (event) { console.log('数据库表数据xml删除成功'); };
requ2.onerror = function (event) { console.log('数据库表数据xml删除成功'); };
}
}
(2). 成功
在新建数据库时,先执行更新,再执行成功。
在数据库存在时,版本号不变的情况下,直接执行成功。
检查表里是否有js文件数据存在,如果存在,就加载把2个文件读取出来 read(),
如果不存在,就获取2个文件getFile(),并存到数据库中。
如果检测失败,也获取这2个文件,因为主键是一样的,会覆盖之前存的这2个文件。
读取数据的方法get()
这里不严谨的是,如果当用户在存储数据时,把网页关闭了,导致2个文件只有一个存储成功了,
(这里xml是小文件,js是大文件),这时,检测时,如果没检测到js文件,就会把2个文件再加载一遍,
如果不想这样,可以,两个文件分别判断是否存在,分别加载。
(我直接把获取2个文件写在一个函数中了,你可以通过传参,分别获取)
request.onsuccess = function (event) {
console.log('数据库打开成功');
db = request.result;
db.onerror = function (event) { console.log("Error creating/accessing IndexedDB database"); };
//是否有表,表里是否有那条数据
var r = db.transaction(['oc']).objectStore('oc').get('js');
r.onsuccess = function(event) {
var d = event.target.result;
if(!d){
console.log('表中无数据,或数据已清空');
getFile();
}
else{
console.log('加载本地保存数据');
read('xml');
read('js');
}
};
r.οnerrοr= function() {
console.log('查询失败');
getFile();
}
};
(3). 错误
在数据库打开失败时,可以页面提示打开失败,或者在控制台打印。
request.onerror = function (event) { console.log('数据库打开报错'); };
(4). 被阻断
打印错误信息
request.onblocked = function() { console.log("Your database version can't be upgraded because the app is open somewhere else.");}
三 .获得文件数据并存储和提取使用
(1) . 获取文件
js文件用blob类型存储。
xml文件用arraybuffer类型存储。
当文件加载成功,将文件存到数据库中 putInDB( 类型,主键);
function getFile(){
var xhr = new XMLHttpRequest();
var xhr2 = new XMLHttpRequest();
var blob,arraybuffer;
xhr.open("GET", 根目录+'/static/oc/oc.js', true);
xhr2.open("GET", 根目录+'/static/oc/hd.xml', true);
xhr.responseType = "blob";
xhr2.responseType = "arraybuffer";
xhr.addEventListener("load", function () {
if (xhr.status === 200) {
blob = xhr.response;
console.log('获取opencv.js成功');
putInDB(blob,'js');
}
}, false);
xhr2.addEventListener("load", function () {
if (xhr2.status === 200) {
console.log('获取xml成功');
arraybuffer = xhr2.response;
putInDB(arraybuffer,'xml');
}
}, false);
xhr.send();
xhr2.send();
}
(2).存储到数据库
这里用到的数据库的事务,事务提供了三种模式:readonly
、readwrite
和 versionchange
。
想要执行写这个操作,用readwrite。
增加一条数据时,add() 方法的调用时,对象仓库中不能存在相同键的对象。
如果新加的这条数据,可以覆盖数据库中本来存在相同键的,用put()方法。
写入完,读取数据,加载使用 read()。
function putInDB(type,id) {
var transaction = db.transaction(["oc"], 'readwrite');
var put = transaction.objectStore('oc').put(type,id);
put.onsuccess = function (event) { console.log('数据'+id+'写入成功'); };
put.onerror = function (event) { console.log('数据'+id+'写入失败'); }
read(id);
}
(3).读取文件
如果是使用js,可以在html或jsp页面内写一个带id的script,用于写入。
(想过写入到某个空的js文件中,再在某个想执行的时候执行,
但浏览器不能让这样做的,如果有更好的写入执行,请留个言指教下 ^-^)
这里对读取出的不同数据做处理
比如读取js文件,用 FileReader.readAsText()方法将数据转变成字符串。
转变完成,写入到script中,用jquery的html()方法写入,就直接执行了。
html: <script type="text/javascript" id="oc"></script>
js:
var xmlreq;
function read(id) {
var req = db.transaction(['oc']).objectStore('oc').get(id);
req.onerror = function(event) { console.log('读取'+id+'数据失败'); };
req.onsuccess = function(event) {
if(id=='xml'){
xmlreq = event.target.result;
let data = new Uint8Array(xmlreq);
// 这里可以处理xml文件数据
}else{
var file = event.target.result;
var reader = new FileReader();
reader.addEventListener("loadend", function() {
//处理数据
$("#oc").html(reader.result);
});
reader.readAsText(file);
}
};
}