H5儲存
1.本地儲存-Web Storage
2.本地儲存-IndexedDB
3.本地儲存的擴充套件介紹
4.離線儲存-app cache
5.總結
分析儲存需求:
- 移動端網路環境因素
- 資料響應慢,體驗下降,2G/3G網速非常慢
- 流量因素
- 客戶端儲存 = 節省流量 = 節省金錢
- 追求原生體驗
- 離線使用應用
- 儲存應用相關資源、資料
Cookie 可行否? 否
因為Cookie 的侷限性:
- 儲存大小限制,僅 4kb 左右
- 單個域名下的數量限制,50個左右
- 汙染請求頭,浪費流量
說明:
- cookie的作用是與伺服器進行互動,作為HTTP規範的一部分而存在 ,
而Web Storage僅僅是為了在本地“儲存”資料而生。 - 每次你請求一個新的頁面的時候Cookie都會被髮送過去,這樣無形中浪費了頻寬。
本地儲存:localStorage 和 sessionStorage
- 相同的使用方法
- 使用 setItem(key,value) 方法設定儲存內容
- 使用 getItem(key) 方法獲取儲存內容
- 使用 removeItem(key) 方法刪除儲存內容
- 使用 clear() 方法清除所有內容
- 使用 length 屬性獲取儲存內容個數
- 使用 key(index) 方法獲取儲存欄位
- 不同的儲存時效
- localStorage 儲存會持久化
- sessionStorage 儲存會在網頁會話結束(標籤頁的關閉)後失效,只有在同一個會話中的頁面才能訪問。
- 不同的儲存容量
- localStorage 容量一般在 2 – 5Mb 左右
- sessionStorage 儲存容量不一,部分瀏覽器不設限
- Web Storage Support Test
http://dev-test.nemikor.com/web-storage/support-test/
sessionStorage和localStorage的儲存空間雖然較大,但是儲存容量仍有限制,叫做配額。
- 使用 Storage 時的注意點:
- 儲存容量超出限制
- 丟擲 QuotaExceededError 異常 (儲存值時應使用 try catch 捕獲異常)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>quota exceed test</title>
</head>
<body>
<button class="start-btn">start</button>
<script>
var btn = document.querySelector('.start-btn');
var data = '01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890',
id = 0,
len = data.length,
total = 0,
key;
function save() {
id = (id + 1) % 10;
key = Date.now() + '' + id;
// try...catch 主要用於捕獲程式碼執行時的異常,並進行異常處理。
// try 部分包含執行時,可能出現異常的程式碼.
// 而 catch 部分包含錯誤發生時執行的程式碼。
try {
// try 中寫可能產生異常的語句
localStorage.setItem(key, data);
save();
} catch (e) {
// catch 中寫負責異常處理的語句
console.log(e.name); //QuotaExceededError
}
}
btn.addEventListener('click', save);
</script>
</body>
</html>
- 儲存型別的限制
- 僅能儲存字串
- 注意型別轉換
JSON.stringify
、JSON.parse
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>quota exceed test</title>
</head>
<body>
<button class="str" onclick="save('abc')">字串 abc</button><br />
<button class="bool" onclick="save(false)">布林值 false</button><br />
<button class="undef" onclick="save(window.undefined)">未定義 window.undefined</button><br />
<button class="null" onclick="save(null)">空值 null</button><br />
<button class="num" onclick="save(0)">數字 0</button><br />
<button class="arr1" onclick="save([])">陣列 []</button><br />
<button class="arr2" onclick="save([1,2,3])">陣列 [1,2,3]</button><br />
<button class="obj1" onclick="save({})">物件 {}</button><br />
<button class="obj2" onclick="save({x: 1})">物件 {x: 1}</button><br />
<button class="obj3" onclick="save({toString: function () {return 'toStringed'}})">物件 {toString: function () {return 'toStringed'}}</button><br />
<button class="obj4" onclick="save({toString: function () {return 100}})">物件 {toString: function () {return 100}}</button><br />
<script>
function save (data) {
localStorage.setItem('key', data)
show(localStorage.getItem('key'))
}
function show (value) {
console.log(value, '|', typeof value)
}
</script>
</body>
</html>
列印結果:
> abc | string
> false | string
> undefined | string
> null | string
> 0 | string
> | string
> 1,2,3 | string
> [object Object] | string
> [object Object] | string
> toStringed | string
> 100 | string
型別轉換:在控制檯輸入
> localStorage.setItem('key',JSON.stringify({data:1}))
< undefined
> localStorage.getItem('key')
< "{"data":1}"
> JSON.parse(localStorage.getItem('key'))
< {data: 1}
- sessionStorage 失效機制
- 重新整理頁面並不會失效
location.reload()
- 相同 URL 不同標籤頁不能共享 sessionStorage
- Web Storage 的優化
效能與儲存容量大小無關,與讀取次數有關
- 減少讀取 item 次數
- 單個 item 中儘可能多的儲存資料
- 帶有過期機制的 localStorage 的功能需求
- 可以設定資料的儲存時間
- 過期資料清理
- 自行維護儲存空間
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>cache storage</title>
</head>
<body>
<script>
'use strict'
;(function () {
var ls = window.localStorage
function oops () {
return console.warn('your browser is not supported localStorage API')
}
function getItem (key) {
var data = ls.getItem(key) //在沒有資料項的情況下,data為null
data = JSON.parse(data)||{} //將字串型別的data轉為物件型別的data
if (data.time === 0) {// 上句如是data = JSON.parse(data),在data.time時,就會報錯。所以調整成data = JSON.parse(data)||{}
// 持久化資料直接返回
return data.value
} else if (Date.now() > data.time) { // 判斷是否超時
//過期
ls.removeItem(key)
return ''
} else {
// 沒過期
return typeof data.value !== 'undefined' ? data.value : ''
}
}
function setItem (key, value, time) {
if (typeof key === 'undefined') {return}
var data = {
time: time ? Date.now() + time : 0,
value: value
}
data = JSON.stringify(data) //stringify方法進行物件的字串序列化
try {
ls.setItem(key, data)
} catch (e) {
ls.clear()
ls.setItem(key, data)
}
}
function removeItem (key) {
ls.removeItem(key)
}
function clear () {
ls.clear()
}
window.cacheStorage = {//瀏覽器支援使用localStorage,不支援輸出提示語
getItem: ls ? getItem : oops,
setItem: ls ? setItem : oops,
removeItem: ls ? removeItem : oops,
clear: ls ? clear : clear
}
})()
</script>
</body>
</html>
IndexedDB 資料庫
1.瞭解indexedDB資料庫
1)indexedDB資料庫是一種事務型資料庫
2)是NoSQL資料庫
3)使用JS物件儲存資料
2.如何建立資料庫和表
- 如何建立資料庫和"表"?
-
indexedDB.open('dbName',dbVersinNumber)
建立資料庫,返回 IDBOpenDBRequest 物件 - indexedDB.createObjectStore 建立“表”
-
indexedDB.deleteDatabase('dbName')
刪除資料庫
function createDB() {
// request 是 IDBOpenDBRequest物件。
request = db.open(dbName, version)
//請求有三種狀態,如下:
request.onsuccess = function() { // 開啟資料庫成功
db = request.result;
console.log('open success');
}
request.onerror = function(e) { // 開啟資料庫失敗
console.log(e.currentTarget.errormessage)
}
request.onupgradeneeded = function(e) { //請求資料庫版本變化時
var store = null;
db = e.target.result;
console.log('upgradeneeded');
/*
if (!db.objectStoreNames.contains(osName)) {
db.createObjectStore(osName, {autoIncrement: true}) // 建立的表的主建是自增型的
}
*/
if (!db.objectStoreNames.contains(osName)) {
store = db.createObjectStore(osName, { keyPath: 'id' }) // 建立的表以欄位為主建
store.createIndex('idIndex', 'id', { unique: true }); //建立索引欄位id唯一
store.createIndex('categoryIndex', 'category', { multiEntry: true }); //建立索引欄位為陣列
store.createIndex('hpIndex', 'hp', { unique: false });
}
}
// onsuccess事件在onupgradeneeded事件之後觸發
}
- 設定主鍵的兩種方法
- 設定自增主鍵 - {autoIncrement: true}
db.createObjectStore(osName, {autoIncrement: true})
- 取資料中欄位作為主鍵 - {keyPath: 欄位名}
store = db.createObjectStore(osName, { keyPath: 'id' })
3. 關於表的增刪改查
- 如何使用事務獲取表
呼叫IDBDatabase.transaction
方法會返回一個 IDBTransaction 物件,
它含有一個 objectStore 方法, 可以讓使用者通過指定模式運算元據庫中的“表”。
indexedDB
-> transaction
-> objectStore
//osName 表格名稱,
var db = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName);
- 事務的模式
- 讀寫模式 -
readwrite
- 只讀模式(預設) -
readonly
- 版本變更模式 -
versionchange
- 關於“表”的增刪查改的相關方法
- 增加資料 –
IDBObjectStore.add
- 獲取資料 –
IDBObjectStore.get
- 獲取所有資料 –
IDBObjectStore.getAll
- 修改(或新增)資料 –
IDBObjectStore.put
- 刪除資料 –
IDBObjectStore.delete
- 清除所有資料 –
IDBObjectStore.clear
這些方法都返回一個IDBRequest
物件。
function addData() {
if (!db) { alert("db"); }
// 呼叫 `IDBDatabase.transaction` 方法會返回一個 IDBTransaction 物件,
// 它含有一個 objectStore 方法, 可以讓使用者通過指定模式運算元據庫中的“表”。
var transaction, store;
transaction = db.transaction(osName, 'readwrite'); //開啟一個事務,讀寫模式
store = transaction.objectStore(osName) ///獲取osName指定的 object store
data.map(function(o) {
store.add(o)
// request = store.add(o) //增加資料
// if (data.length - 1 === i) {
// request.onsuccess = function () {
// console.log('alreay add all data to db')
// showCurrentData()
// }
// }
})
}
function getData(id) {
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName);
var request = store.get(id);
request.onsuccess = function() {
console.log(request.result);
}
}
function getAllData() {
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName);
var request = store.getAll();
request.onsuccess = function() {
console.log(request.result);
}
}
function updateData(id) {
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName);
var request = store.get(id);
request.onsuccess = function() {
request = store.put({ //更新即可以更新也可以新增,取決於關鍵字是否有重複
name: '小花貓',
id: id,
hp: 9
});
}
}
function deleteData(id) {
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName);
var request = store.delete(id);
request.onsuccess = function() {
console.log('delete success');
}
}
function clear() {
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName);
var request = store.clear();
request.onsuccess = function() {
console.log('clear success');
}
}
- IDBRequest 物件
- 使用
IDBRequest.onsuccess
執行查詢完成回撥 - 使用
IDBRequest.result
獲取查詢結果 - 使用
IDBRequest.onerror
執行查詢失敗回撥
4. 關於索引
- 如何建立索引
IDBObjectStore.createIndex
- indexName: 索引名稱
- keyPath: 索引欄位,可以為空或者陣列(type array)
- optionParameters: 索引配置引數
store = db.createObjectStore(osName, { keyPath: 'id' }) // 建立的表以欄位為主建
store.createIndex('idIndex', 'id', { unique: true }); //建立索引欄位id唯一
store.createIndex('categoryIndex', 'category', { multiEntry: true }); //建立索引欄位為陣列
store.createIndex('hpIndex', 'hp', { unique: false });
- optionParameters: 索引配置引數
- unique 表示keyPath欄位的資料是否唯一
2)multiEntry 表示是否為 keyPath 欄位的每一項建立一條索引資料
- 使用索引的好處
- 可以使用儲存記錄中的值進行檢索
- 索引自動更新
- 索引資料自動排序
- 索引的相關方法
1)查詢資料 - IDBIndex.get
- 查詢所有資料 - IDBIndex.getAll
- 開啟遊標 - IDBIndex.openCursor
function useIndexGetData() { // 索引只能查詢資料,並不能運算元據
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName),
index = store.index('categoryIndex');
request = index.getAll('飛行');
request.onsuccess = function() {
console.log(request.result);
}
}
5. 關於遊標
- 如何建立遊標?
IDBObjectStore/IDBIndex.openCursor
- 接收可選引數 range 和 direction,指明遊標遍歷的範圍和方向
- 返回一個 IDBRequet 物件,非同步方法
- 該 IDBRequet 物件的結果是一個 IDBCursor 物件
- IDBKeyRange 物件
1)upperBound: 指定遊標範圍的上限
2)lowerBound: 指定遊標範圍的下限
3)bound: 指定遊標範圍的區間
4)only: 指定遊標的值
key range 取值表:
- direction 引數
- next: 順序查詢
- nextunique: 順序唯一查詢
- prev: 逆序查詢
- prevunique: 逆序唯一查詢
function useCursorGetData() {
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName),
// request=store.openCursor(); //建立遊標
// request=store.openCursor(IDBKeyRange.only('002')); //指定遊標KeyRange,only一個
// request = store.openCursor(null, 'prev');
request = store.openCursor(IDBKeyRange.lowerBound('002'), 'prev'); //逆序查詢,遊標範圍下限是"002"
request.onsuccess = function() {
var cursor = request.result;
if (cursor) {
console.log(cursor.value);
cursor.continue();
}
}
}
6. 索引和遊標的結合使用
- 索引和遊標的優勢
索引:可以按值搜尋
遊標:可以選擇遍歷順序及運算元據
function useIndexAndCursorOperateData1() { // 索引和遊標結合,可以查詢和運算元據
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName),
index=store.index('categoryIndex');
request=index.openCursor();
request.onsuccess = function() {
var cursor = request.result;
if (cursor) {
if(cursor.value.id==='002'){
/* // 更新資料
cursor.update({
name: '小蝙蝠',
id: '002',
hp: 10,
category:['怪物','飛行']
})
*/
// 刪除資料
cursor.delete().onsuccess=function () {
console.log('delete success');
}
}
// 更新資料和刪除資料操作都是非同步操作,所以輸出可能會混亂
console.log(cursor.value);
cursor.continue();
}
}
}
function useIndexAndCursorOperateData() { // 索引和遊標結合,可以查詢和運算元據
var transaction = db.transaction(osName, 'readwrite'), //開啟一個事務,讀寫模式
store = transaction.objectStore(osName),
index = store.index('hpIndex');
// request = index.openCursor(IDBKeyRange.upperBound(5)); // 5(包含5)以下
request = index.openCursor(IDBKeyRange.bound(5,10,true,true)); // 範圍(5到10)
request.onsuccess = function() {
var cursor = request.result,value=null;
if (cursor) {
value = cursor.value;
value.hp += 20;
cursor.update(value);
console.log(cursor.value);
cursor.continue();
}
}
}
IndexedDB 與 Web Storage 比較
- indexedDB 的優勢:
- 儲存型別更加豐富
- 可實現高階查詢
- 可在 Web Workers 中使用
- 儲存容量更大
- Web Storage 的優勢
- API 較少,更容易掌握
- 相容性更好
- IndexedDB 的相容性問題
1)IOS8 & 9 中 webview 不支援 indexedDB
2)Firefox 單次儲存 Blob 資料超 50Mb 會丟擲異常, 這個50M可以在IndexDB的一些API中進行修改
3)Safari 的 indexedDB 不能用於 web workers
4)Chrome36 不支援儲存型別的資料
其他儲存方式介紹
1. WebSQL
- 關係型資料庫
- 隨HTML5規範加入, 在瀏覽器端執行的輕量級資料庫。
- WebSQL 的 API 有哪些?
- openDatabase: 開啟資料庫
- transaction: 獲取事務,進行資料庫操作
- executeSql: 執行 SQL 進行查詢
- WebSQL 的現狀
-
相容性問題嚴重
W3C 已經不再積極處理其相關規範(避免使用WebSQL)
2. Filesystem & FileWriter API
- 供我們在客戶端進行檔案的儲存
-
但是和WebSQL有相似的命運,有嚴重的相容性問題和規範被廢棄(避免使用)。
3. UserData
是IE獨有的儲存方式:
- 只在Windows系統的IE中存在
- 容量不大
4. Cookie
- 儲存大小限制,僅 4kb 左右
- 單個域名下的數量限制,50個左右
- 汙染請求頭,浪費流量
相關文章
- H5本地儲存:sessionStorage和localStorageH5Session
- 塊儲存 檔案儲存 物件儲存物件
- 微信H5頁儲存當前頁面為圖片踩坑H5
- 行式儲存 列式儲存
- 儲存—物件儲存_Minio物件
- 自動儲存、靜態儲存和動態儲存
- 一次 H5 「儲存頁面為圖片」 的踩坑之旅H5
- MyISAM 儲存引擎,Innodb 儲存引擎儲存引擎
- 資料儲存--檔案儲存
- 儲存
- 物件儲存 vs 檔案儲存 vs 塊儲存,選哪個?物件
- 儲存過程與儲存函式儲存過程儲存函式
- PostgreSQL儲存智慧-空間聚集儲存SQL
- Redis儲存結構以及儲存格式Redis
- 聚焦資料時代新儲存需求,浪潮儲存的新儲存之道
- 一文徹底解決H5頁面中長按儲存圖片H5
- 雲原生儲存詳解:容器儲存與 K8s 儲存卷K8S
- mysql儲存函過程和儲存函式都屬於儲存程式MySql儲存函式
- 物件儲存,未來儲存新潮流物件
- Android儲存(2)– 介面卡儲存Android
- Flutter持久化儲存之檔案儲存Flutter持久化
- 容器附加儲存(CAS)是雲原生儲存
- 儲存引擎儲存引擎
- 照片儲存
- 儲存管理
- 物件儲存物件
- 儲存Word
- 【儲存】EMC
- 本地儲存
- 【Java】儲存Java
- HDS儲存
- 儲存概述
- 儲存lun
- MySQL儲存MySql
- 段式儲存
- 儲存器
- 微信H5實現網頁長按儲存圖片及識別二維碼H5網頁
- Flutter持久化儲存之key-value儲存Flutter持久化