HTML5 離線存儲(chǔ)
本章介紹一下 HTML5 新增的離線存儲(chǔ)特性 Localstorage,主要包括 Localstorage 的發(fā)展史、兼容性、優(yōu)缺點(diǎn)以及使用場景。
說到 Localstorage,為什么要使用 Localstorage 呢?
因?yàn)殚_發(fā)程序當(dāng)然就要存儲(chǔ)數(shù)據(jù)了,但是 Web 開發(fā)場景比較特殊,數(shù)據(jù)正常情況下是要通過 HTTP 協(xié)議發(fā)送給服務(wù)器端,存儲(chǔ)在服務(wù)器上,但是呢,如果所有數(shù)據(jù)都存到服務(wù)器一方面會(huì)浪費(fèi)服務(wù)器資源,另一方面也會(huì)降低網(wǎng)頁響應(yīng)速度,所以設(shè)計(jì)網(wǎng)頁時(shí)會(huì)抽取一些不太重要的或者臨時(shí)性的數(shù)據(jù)使用離線存儲(chǔ)方式放在瀏覽器上。
總的來說,Localstorage 是一個(gè)簡單的離線存儲(chǔ)技術(shù),通過官方提供的增刪改查的 API 可以方便的操作它,需要考慮的難點(diǎn)是每個(gè)瀏覽器的容量限制,使用時(shí)做好容錯(cuò)即可。
1. 離線存儲(chǔ)發(fā)展史
在早期的互聯(lián)網(wǎng)發(fā)展中,瀏覽器制定了不同的標(biāo)準(zhǔn)用于存儲(chǔ)離線數(shù)據(jù),其中比較出名的有微軟 IE 瀏覽器的 userData(單個(gè)頁面可存儲(chǔ) 64 kb)、Adobe 的 flash6 中的 flash-cookies(允許存儲(chǔ) 100kb)、flash8 中的 externalinterface、Google 的 gears,不幸的是這些技術(shù)沒有統(tǒng)一的標(biāo)準(zhǔn),而且只適用于單一的瀏覽器,不能跨平臺(tái),所以沒有收錄在 HTML 標(biāo)準(zhǔn)中。HTML5 之前,Cookie 是唯一在 HTML 標(biāo)準(zhǔn)中用于離線存儲(chǔ)的技術(shù),但是 Cookie 有一些不太友好的特征限制了它的應(yīng)用場景:
- Cookie 會(huì)被附加在 HTTP 協(xié)議中,每次請(qǐng)求都會(huì)被發(fā)送到服務(wù)器端,增加了不必要的流量損耗
- Cookie 大小限制在 4kb 左右(不同的瀏覽器有一些區(qū)別),對(duì)于一些復(fù)雜的業(yè)務(wù)場景可能不夠
這兩個(gè)缺點(diǎn)在 Localstorage 中得到了有效的解決,下面我們就開始學(xué)習(xí) Localstorage。
2. 兼容性
截止目前為止,已經(jīng)有大部分瀏覽器已經(jīng)支持 Localstorage,包括 IE8。
具體瀏覽器是否支持 Localstorage 可以通過簡單的 JavaScript 代碼判斷。
function testLocalstorage(){
if ( typeof window.localStorage == "object" ) return true;//判斷l(xiāng)ocalstorage對(duì)象是否定義
else return false;//未定義返回false
}
3. API 接口
Localstorage 是一個(gè)簡單的 key/value 形式的數(shù)據(jù)庫,以鍵值對(duì)的方式存儲(chǔ),所以提供的接口主要是基于 k/v 的操作?;谔峁┑慕涌谥荒艽鎯?chǔ)簡單的一維數(shù)組,但是有些業(yè)務(wù)場景可能會(huì)牽涉到多維數(shù)據(jù)甚至對(duì)象的存儲(chǔ),怎么辦?
- 建議使用
JSON.stringify()
將數(shù)據(jù)轉(zhuǎn)化成字符串方式再存儲(chǔ); - 使用復(fù)雜的前端數(shù)據(jù)庫,例如 indexDB,具體不做深入討論。
3.1 存儲(chǔ)數(shù)據(jù)
window.localStorage.setItem("test",1)//設(shè)置key=test的值為1
localStorage.setItem("test",1)//設(shè)置key=test的值為1,localstorage可以作為全局對(duì)象處理
localStorage.test = 1//可以通過屬性值的方式直接操作localstorage的key
運(yùn)行下面案例代碼,試一試:
<!DOCTYPE html>
<html>
<body>
<p id="demo"></p>
<script>
window.localStorage.setItem("test",1)//設(shè)置key=test的值為1
localStorage.setItem("test",1)//設(shè)置key=test的值為1,localstorage可以作為全局對(duì)象處理
localStorage.test = 1//可以通過屬性值的方式直接操作localstorage的key
document.getElementById("demo").innerHTML =
"localStorage.test 的值是" + localStorage.test + "。";
</script>
</body>
</html>
3.2 讀取數(shù)據(jù)-按鍵值
getItem
var a = window.localStorage.getItem("test")//獲取key=test的值
var a = localStorage.test//可以直接通過對(duì)象屬性的方式操作
如果獲取一個(gè)不存在的 key 返回 null ,下同。
3.3 讀取數(shù)據(jù)-按位置
var a = window.localStorage.key(0)//可以根據(jù)key在localstorage的位置的方式操作,類似操作JavaScript的array的方式
3.4 刪除數(shù)據(jù)
window.localStorage.removeItem("test")//刪除key=test的值
window.localStorage.test = ''//可以通過賦空值的方式等價(jià)操作
3.5 整體清空
window.localStorage.clear()//clear函數(shù)清空整個(gè)localstorage
3.6 存儲(chǔ)事件監(jiān)聽
當(dāng) localstorage 發(fā)生改變時(shí),可以通過監(jiān)聽 storage 事件作出相應(yīng)的業(yè)務(wù)處理。
if (window.addEventListener) { //通過addEventListener方式監(jiān)聽事件,為了兼容IE
window.addEventListener("storage", function(e){//監(jiān)聽storage事件
//業(yè)務(wù)處理
}, false);
} else {
window.attachEvent("onstorage", function(e){//通過attachEvent方式監(jiān)聽事件
//業(yè)務(wù)處理
});
}
4. 適用場景及局限性
4.1 局限性
前邊提到 Localstorage 相比較 Cookie 的優(yōu)勢是容量大和節(jié)省 HTTP 帶寬,但是它還是有自身的缺點(diǎn),下邊羅列了它的缺點(diǎn)
- 5M 容量依然小,用過數(shù)據(jù)庫的同學(xué)應(yīng)該知道,MySQL 隨便一個(gè)表加上索引很容易超過 5M
- 不能跨域名訪問,同一個(gè)網(wǎng)站可能會(huì)牽涉到子域名
- 不能存儲(chǔ)關(guān)系型數(shù)據(jù)
- 不能搜索
4.2 適用場景
那么以上缺點(diǎn)有沒有解決方案,肯定是有的,例如 HTML 的 webSql 或者 indexDB,那肯定有人問了,為什么不直接用最復(fù)雜的數(shù)據(jù)庫,跳過 Localstorage 呢?原因是技術(shù)沒有最好的,只有最適合的,不同的業(yè)務(wù)場景應(yīng)該選擇最匹配的而且成本最小的解決方案。例如你在存儲(chǔ)簡單的業(yè)務(wù)場景中的臨時(shí)數(shù)據(jù)時(shí)完全可以使用 Localstorage 甚至 Cookie 搞定,假如使用 indexDB 的話系統(tǒng)的開發(fā)成本以及維護(hù)成本會(huì)翻番,得不償失。
所以說總結(jié)下來 Localstorage 的適用業(yè)務(wù)場景是:
- 數(shù)據(jù)關(guān)系簡單明了
- 數(shù)據(jù)量小
- 數(shù)據(jù)無需持久化存儲(chǔ)且不需要考慮安全性
- 無需跟服務(wù)器交互
5. 業(yè)務(wù)實(shí)戰(zhàn)
5.1 項(xiàng)目使用場景
之前開發(fā)一個(gè)場館管理系統(tǒng)時(shí)有一個(gè)功能是根據(jù)用戶輸入的關(guān)鍵字搜索場館,業(yè)務(wù)方的需求是需要臨時(shí)保留搜索關(guān)鍵詞的歷史記錄,考慮到是臨時(shí)保存,而且只保存關(guān)鍵字不需要復(fù)雜的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)且只保存 10 條最新的數(shù)據(jù),項(xiàng)目組商量下來決定使用 Localstorage 保存,搜索成功之后添加到歷史記錄。
function chooseClubItem(e) {
let mid = e.currentTarget.dataset.id
let findAddressInfo = this.data.markers.find(item => item.id === mid)
const historyList = window.localStorage.getItem('historyList') || []//獲取localstorage需要操作的鍵值
if (findAddressInfo) {
const index = historyList.findIndex(history => history.id == findAddressInfo.id)
if (index !== -1) {
historyList.splice(index, 1)
}
if(historyList.length>=10)historyList.pop();//超過最大歷史數(shù)目,刪除最后一個(gè)
historyList.unshift(findAddressInfo)//加入到歷史存儲(chǔ)隊(duì)列中
window.localStorage.setItem('historyList', historyList)//設(shè)置離線存儲(chǔ)
}
},
清空歷史記錄
function delHistory() {
let that = this
showModal({//彈出確認(rèn)對(duì)話框
title: '',
content: '您確定要清空搜索歷史嗎',
showCancel: true,
cancelText: '取消',
cancelColor: '#000000',
confirmText: '確定',
confirmColor: '#3CC51F',
success: result => {
if (result.confirm) {
window.localStorage.removeItem("historyList")//情況歷史隊(duì)列
}
}
})
},
5.2 使用第三方庫
現(xiàn)實(shí)中考慮到瀏覽器對(duì) Localstorage 畢竟不是百分之百兼容,而且 Localstorage 本身提供的 API 比較簡單,所以實(shí)際項(xiàng)目中可以考慮使用第三方封裝庫操作,比如 store.js。
store.js 優(yōu)先選擇 localStorage 來進(jìn)行存儲(chǔ),在 IE6 和 IE7 下降級(jí)使用 userData 來達(dá)到目的。 沒有使用 flash ,不會(huì)減慢你的頁面加載速度。也沒有使用 Cookies ,不會(huì)使你的網(wǎng)絡(luò)請(qǐng)求變得臃腫。store.js 依賴 JSON 來序列化數(shù)據(jù)進(jìn)行存儲(chǔ)。
6. 總結(jié)
以上介紹了 Localstorage 和傳統(tǒng)離線存儲(chǔ)的優(yōu)缺點(diǎn)對(duì)比,Localstorage 的使用方法以及項(xiàng)目實(shí)戰(zhàn)分析??偟膩碚f Localstorage 適用于業(yè)務(wù)簡單的輕量級(jí)存儲(chǔ)中,通過簡單的 API 操作增刪改查存儲(chǔ)鍵值對(duì),而且可以通過事件監(jiān)聽的方式獲取 Localstorage 的操作事件,無需發(fā)送 HTTP 請(qǐng)求,真正實(shí)現(xiàn)了離線存儲(chǔ)