网潘货区:PHP+Go 开发仿简书,实战高并发高可用微服务架构王盘分xiang
<p>JavaScript IndexedDB齐全指南
本文将通过一个小型的crmeb教程向您介绍IndexedDB,并将IndexedDB与其余可用选项进行比拟。IndexedDB用于在浏览器中存储数据,尤其实用于须要脱机工作的web应用程序(比方大多数高级web应用程序)。
首先,让咱们介绍一下为什么咱们须要在web浏览器中存储数据。数据在web应用程序中无处不在——用户通过交互来创立数据、查找数据、更新数据和删除数据。如果没有方法存储这些数据,就不可能容许用户交互在多个web应用程序的应用中放弃状态。你通常应用MySQL、Postgres、MongoDB、Secondary、ArangoDB等数据库来解决这些存储,然而如果你想让利用离线工作呢?
这在开发web应用程序时尤其重要,web应用程序复制了原生应用程序的感觉,但位于浏览器中。这些渐进式web应用程序必须离线工作,因而它们须要一个存储选项。侥幸的是,有几个对于如何在浏览器中存储数据的工具,能够在线和离线拜访数据。
1.浏览器存储模式
至于如何在浏览器中存储数据,Web规范提供了三个次要的API:
Cookies:这些数据存储在浏览器中。Cookies的大小限度为4k。通常当服务器响应一个申请时,它们可能蕴含一个SET-COOKIE头,让浏览器存储一个键和值。而后,客户机应该在未来的申请头中蕴含这个cookie,这将容许服务器辨认浏览器会话等。这些cookie通常具备HTTP-Only属性,这意味着不能通过客户端脚本拜访cookie。这使得cookie不是保留离线数据的好抉择。
本地存储/会话存储:本地存储/会话存储是浏览器内置的键值存储,其中每个键的大小限度为5MB。LocalStorage存储数据,直到它被删除,而sessionStorage将在浏览器敞开时主动革除。否则,它们的API是雷同的。能够应用window . local storage . setitem(" key "," value ")增加键值对。并应用window . local storage . getitem(" key ")检索一个值。留神,LocalStorage API是同步的,所以应用它会阻塞浏览器中的其余流动,这可能是一个问题。
IndexedDB:内置于浏览器中的残缺文档数据库,没有存储限度。它容许您异步拜访数据,这对于避免简单操作阻塞演示和其余流动十分无效。这是咱们上面要深刻探讨的。
在这些办法中,localStorage操作简略,存储数据量小,是一个不错的抉择。对于更简单或惯例的操作,IndexedDB可能是更好的抉择,尤其是当您须要异步获取数据时。
IndexedDB API比LocalStorage API更简单。因而,让咱们用IndexedDB构建一些货色,让您更好地理解它是如何工作的!
2.用例
创立一个新的HTML文件,咱们称之为index.html,内容如下:
索引数据库待办事项列表
注释{
文本对齐:居中;
}
h1 {
色彩:棕色;
}
索引数据库待办事项列表
增加待办事项
//保留输出变量
const textInput = document . query selector("[type = ' text ']")
const button = document . query selector(" button ")
//保留todos的数组
const todos = []
//出现todos '函数
函数renderTodos(){
const ul = document . query selector(" # todos ul ")
ul.innerHTML = " "
对于(todos的todo){
ul.innerHTML += ${todo}
}
}
renderTodos()
复制代码
当初咱们能够开始设置IndexedDB了。在浏览器中关上此文件。如果应用的是VS代码,能够应用liveserver这样的扩大。
IndexedDB反对很好,然而咱们还是想检查一下浏览器是否反对API的实现,这样你能够增加以下函数来查看。
//查看indexedDB实现并返回其函数
函数getIndexDB() {
常数索引DB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB ||
window.shimIndexedDB
if (indexedDB){
返回索引b
}
console.error("此浏览器不反对indexedDB ")
返回null
}
复制代码
此函数返回IndexedDB的浏览器实现或浏览器不反对的日志。能够在浏览器中记录调用getIndexDB的后果,确认浏览器反对IndexedDB。
您能够在上面看到兼容性列表。你能够在这里找到残缺的列表,包含挪动浏览器。
当初让咱们用indexeddb.open ("database name ",1)关上一个数据库。open的第一个参数是数据库的名称,第二个参数是数据库的版本。如果您心愿触发onupgraderequired,您应该减少。公开通话。open办法将返回一个具备多个属性的对象,包含onerror、onupgradenneeded和onsuccess。每个属性都承受一个回调函数,该函数在相干事件产生时执行。
const indexedDB = getIndexDB()
// console.log(indexedDB)
const request = indexed db . open(" todo db ",1)
console.log(申请)
render todos();
复制代码
您应该会看到带有IDBOpenDBRequest对象的console.log。IndexedDB是基于事件的,这合乎它的异步模型。接下来,让咱们看一下数据库启动时可能产生的事件。首先,咱们将侦听request.onerror事件,以避免在拜访数据库时呈现任何谬误。
const indexedDB = getIndexDB()
// console.log(indexedDB)
const request = indexed db . open(" todo db ",1)
//console.log(申请)
//on错误处理
request . on Error =(event)= > console . Error(" IndexDB Error:",event)
render todos();
复制代码
咱们将监督的下一个事件是request.onupgradeneeded事件,当咱们尝试关上版本号高于数据库以后版本号的数据库时,该事件将运行。这是创立存储/表及其模式的性能。该性能在每个版本号下只执行一次。因而,如果您决定更改onupgradedened回调来更新您的模式或创立新的存储,那么版本号也应该在下一个。公开通话。存储实质上相当于传统数据库中的表。
const indexed db = getIndexDB();
// console.log(indexedDB)
const request = indexed db . open(" todo db ",1);
//console.log(申请)
//on错误处理
request . on Error =(event)= > console . Error(" IndexDB Error:",event);
//onupgradereneed
request . onupgradereneed =(){
//获取数据库连贯
const db = request.result
//定义新的存储
const store = db . createobjectstore(" todos " ,{
keyPath: "id ",
主动增量:真,
});
//指定一个属性作为索引
store.createIndex("todos_text ",["text"],{unique: false})
};
render todos();
复制代码
在onupgradeneeded中,咱们做了以下工作:
获取数据库对象(如果onupgradenneeded函数正在运行,您晓得它是可用的)
创立一个名为todos的新存储/表/汇合,它的键id是一个主动递增的数字(记录的惟一标识符)
将todos_text指定为索引,这容许咱们稍后通过todos_text搜寻数据库。如果您不打算按特定属性进行搜寻,那么您不用创立索引。
最初,解决request.onsuccess事件,该事件在数据库连贯并存储所有设置和配置后运行。您能够利用这个机会提取todo列表,并将它们注入到咱们的数组中。
//onsuccess
request.onsuccess = () {
console.log("数据库连贯已建设")
//获取数据库连贯
常量db = request.result
//创立一个事务对象
const tx = db.transaction("todos "," readwrite ")
//创立一个存储在咱们这里的事务
const todos store = tx . objectstore(" todos ")
//获取所有待办事项
const query = todosStore.getAll()
//应用数据查问
query.onsuccess = () {
console.log("所有待办事项: ",query.result)
for(query . result的todo
todos.push(todo.text)
}
renderTodos()
}
}
复制代码
咱们胜利地做到了以下几点:
获取数据库连贯
创立交易记录
指定咱们进行交易的存储。
运行getAll查问以获取存储中的所有文档/记录。
在查问特定的onsuccess事件时,咱们遍历todos,将它们存储在todos数组中并调用renderTodos(),因而它们被出现到dom中。
您应该在控制台中看到一个蕴含空数组的console.log。
- 谬误提醒: *如果您运行的是热重装web服务器,如liveserver,您可能会看到谬误“无存储”。这是因为onupgradedneeded函数是在您写完函数之前执行的。因而,对于该版本号,不会再次执行。解决办法是减少表的版本号,这将创立一个onupgradereneed,onupgradereneed回调将在下一次页面刷新时执行。
当初咱们曾经有了数据库设置,咱们能够依照雷同的模式来解决咱们心愿产生的任何其余事件。例如,让咱们在单击按钮时创立一个事件,该事件不仅会向dom增加一个新的todo,还会向数据库增加一个新的todo,以便在页面刷新时显示。
//按钮事件
button.addEventListener("click ",(event) => {
//设置一个事务
常量db = request.result
const tx = db.transaction("todos "," readwrite ")
const todos store = tx . objectstore(" todos ")
//增加一个todo
const text = textInput.value
Todos.push(text) //将todo增加到数组中
TodosStore.put({text}) //增加到indexedDB
RenderTodos() //更新dom
})
复制代码
当初你能够增加todos了,因为你用的是IndexedDB,无论你在线还是离线都能够。
增加一些todo,当您刷新页面时,您会看到todo依然存在。它们还显示在查问后果的console.log中,并且每个todo都有一个惟一的ID。到目前为止,残缺的代码应该是这样的:
索引数据库待办事项列表
注释{
文本对齐:居中;
}
h1 {
色彩:棕色;
}
索引数据库待办事项列表
增加待办事项
//保留输出变量
const textInput = document . query selector("[type = ' text ']");
const button = document . query selector(" button ");
//保留todos的数组
const todos =[];
//出现todos '函数
函数renderTodos() {
const ul = document . query selector(" # todos ul ");
ul.innerHTML =
对于(todos的todo){
ul . innerhtml+= $ { todo }
;
}
}
//查看indexedDB实现并返回其函数
函数getIndexDB() {
常数索引DB =
window.indexedDB ||
window.mozIndexedDB ||
window.webkitIndexedDB ||
window.msIndexedDB ||
window.shimIndexedDB
if (indexedDB) {
返回indexedDB
}
console.log("此浏览器不反对indexed db ");
返回null
}
const indexed db = getIndexDB();
// console.log(indexedDB)
const request = indexed db . open(" todo db ",2);
// console.log(申请)
//on错误处理
request . on Error =(event)= > console . Error(" IndexDB Error:",event);
//onupgradereneed
request . onupgradereneed =(){
//获取数据库连贯
const db = request.result
//定义新的存储
const store = db . createobjectstore(" todos " ,{
keyPath: "id ",
主动增量:真,
});
//指定一个属性作为索引
store.createIndex("todos_text ",["text"],{unique: false})
};
// onsuccess
request.onsuccess = () {
console.log("数据库连贯已建设")
//获取数据库连贯
常量db = request.result
//创立一个事务对象
const tx = db.transaction("todos "," readwrite ")
//创立咱们的存储事务之一
const todos store = tx . objectstore(" todos ")
//获取所有待办事项
const query = todosStore.getAll()
//应用数据查问
query.onsuccess = () {
console.log("所有待办事项: ",query.result)
for(query . result的todo
todos.push(todo.text)
}
renderTodos()
}
}
//按钮事件
button.addEventListener("click ",(event) => {
//设置一个事务
常量db = request.result
const tx = db.transaction("todos "," readwrite ")
const todos store = tx . objectstore(" todos ")
//增加一个todo
const text = textInput.value
Todos.push(text) //将todo增加到数组中
TodosStore.put({text}) //增加到indexedDB
RenderTodos() //更新dom
})
render todos();
复制代码
todosStore对象上可用于不同类型事务的其余办法:
革除:删除商店中的所有记录。
增加:插入具备给定id的记录(如果它曾经存在,将会呈现谬误)
Put:插入或更新具备给定id的记录(如果它曾经存在,它将被更新)
Get:获取具备特定id的记录。
获取商店的所有记录。
Count:返回存储中的记录数。
CreateIndex:依据要查问的给定索引创立一个对象。
删除:删除给定id的记录
3.性能和其余思考因素
您须要思考以下几点:
并非所有浏览器都反对将文件存储为blob。您会找到一个更好的办法:将它们存储为arraybuffer。
某些浏览器可能不反对在私人浏览模式下写入IndexedDB。
IndexedDB在写对象的时候会创立结构化克隆,这会阻塞主线程,所以如果你的大对象被更多的嵌套对象填充,这可能会造成一些提早。
如果用户敞开浏览器,任何未实现的事务都可能被停止。
如果另一个浏览器选项卡关上一个具备较新数据库版本号的应用程序,它将被阻止降级,直到所有旧版本选项卡被敞开/从新加载。侥幸的是,您能够应用onblocked事件来触发警报,告诉用户他们须要这样做。
只管indexedDB非常适合让您的应用程序脱机工作,但它不应该是您的次要数据存储。在互联网连贯中,您可能心愿将indexedDB与内部数据库同步,以便在用户革除浏览器数据时不会失落用户的信息。</p>